diff --git a/beestation.dme b/beestation.dme index eff34a4864dbb..c8594a02e927b 100644 --- a/beestation.dme +++ b/beestation.dme @@ -457,6 +457,7 @@ #include "code\controllers\subsystem\radio.dm" #include "code\controllers\subsystem\research.dm" #include "code\controllers\subsystem\runechat.dm" +#include "code\controllers\subsystem\security_level.dm" #include "code\controllers\subsystem\server_maint.dm" #include "code\controllers\subsystem\shuttle.dm" #include "code\controllers\subsystem\sound.dm" @@ -3834,7 +3835,7 @@ #include "code\modules\security\prison_scanner.dm" #include "code\modules\security\workshop.dm" #include "code\modules\security_levels\keycard_authentication.dm" -#include "code\modules\security_levels\security_levels.dm" +#include "code\modules\security_levels\security_level_datums.dm" #include "code\modules\shuttle\arrivals.dm" #include "code\modules\shuttle\assault_pod.dm" #include "code\modules\shuttle\custom_shuttle.dm" diff --git a/code/__DEFINES/dcs/signals/signals_datum/signals_datum.dm b/code/__DEFINES/dcs/signals/signals_datum/signals_datum.dm index 55808c4f5d436..e9fc41ba61575 100644 --- a/code/__DEFINES/dcs/signals/signals_datum/signals_datum.dm +++ b/code/__DEFINES/dcs/signals/signals_datum/signals_datum.dm @@ -91,6 +91,9 @@ ///From base of datum/controller/subsystem/Initialize #define COMSIG_SUBSYSTEM_POST_INITIALIZE "subsystem_post_initialize" +///from SSsecurity_level when the security level changes : (new_level) +#define COMSIG_SECURITY_LEVEL_CHANGED "security_level_changed" + /// a weather event of some kind occured #define COMSIG_WEATHER_TELEGRAPH(event_type) "!weather_telegraph [event_type]" #define COMSIG_WEATHER_START(event_type) "!weather_start [event_type]" diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index 132dee7e28ea9..1d10a44148fb3 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -12,7 +12,6 @@ #define COMSIG_GLOB_MOB_DEATH "!mob_death" //! mob died somewhere : (mob , gibbed) #define COMSIG_GLOB_LIVING_SAY_SPECIAL "!say_special" //! global living say plug - use sparingly: (mob/speaker , message) #define COMSIG_GLOB_CARBON_THROW_THING "!throw_thing" //! a person somewhere has thrown something : (mob/living/carbon/carbon_thrower, target) -#define COMSIG_GLOB_SECURITY_ALERT_CHANGE "!alert_change" //! security level was changed : (new_alert) #define COMSIG_GLOB_SOUND_PLAYED "!sound_played" //! a sound was played : (sound_player, sound_file) /// called by datum/cinematic/play() : (datum/cinematic/new_cinematic) #define COMSIG_GLOB_PLAY_CINEMATIC "!play_cinematic" diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm index 4e4c82190daf1..a716c5eab7d22 100644 --- a/code/__DEFINES/shuttles.dm +++ b/code/__DEFINES/shuttles.dm @@ -53,6 +53,14 @@ #define ENGINE_COEFF_MAX 2 #define ENGINE_DEFAULT_MAXSPEED_ENGINES 5 +// Alert level related +#define ALERT_COEFF_AUTOEVAC_NORMAL 2.5 +#define ALERT_COEFF_GREEN 2 +#define ALERT_COEFF_BLUE 1 +#define ALERT_COEFF_RED 0.5 +#define ALERT_COEFF_AUTOEVAC_CRITICAL 0.4 +#define ALERT_COEFF_DELTA 0.25 + //Docking error flags #define DOCKING_SUCCESS 0 #define DOCKING_BLOCKED (1<<0) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 71f4fbb4b7606..b024f21c04a24 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -136,6 +136,7 @@ #define INIT_ORDER_INSTRUMENTS 82 #define INIT_ORDER_GREYSCALE 81 #define INIT_ORDER_VIS 80 +#define INIT_ORDER_SECURITY_LEVEL 79 // We need to load before events so that it has a security level to choose from. #define INIT_ORDER_ACHIEVEMENTS 77 #define INIT_ORDER_RESEARCH 75 #define INIT_ORDER_ORBITS 74 //Other things use the orbital map, so it needs to be made early on. diff --git a/code/__HELPERS/priority_announce.dm b/code/__HELPERS/priority_announce.dm index c7a494b4e82e2..5025198209d57 100644 --- a/code/__HELPERS/priority_announce.dm +++ b/code/__HELPERS/priority_announce.dm @@ -75,7 +75,20 @@ SScommunications.send_message(M) -/proc/minor_announce(message, title = "Attention:", alert, from, html_encode = TRUE) +/** + * Sends a minor annoucement to players. + * Minor announcements are large text, with the title in red and message in white. + * Only mobs that can hear can see the announcements. + * + * message - the message contents of the announcement. + * title - the title of the announcement, which is often "who sent it". + * alert - whether this announcement is an alert, or just a notice. Only changes the sound that is played by default. + * from - who sent the announcement, in the case of communications consoles or the like. + * html_encode - if TRUE, we will html encode our title and message before sending it, to prevent player input abuse. + * players - optional, a list mobs to send the announcement to. If unset, sends to all players. + * sound_override - optional, use the passed sound file instead of the default notice sounds. + */ +/proc/minor_announce(message, title = "Attention:", alert, from, html_encode = TRUE, list/players, sound_override) if(!message) return @@ -83,16 +96,21 @@ title = html_encode(title) message = html_encode(message) - for(var/mob/M in GLOB.player_list) - if(!isnewplayer(M) && M.can_hear()) - var/complete_msg = "[title]
[message]

" - if(from) - complete_msg += "-[from]" - to_chat(M, complete_msg) - if(M.client.prefs.read_player_preference(/datum/preference/toggle/sound_announcements)) - if(alert) - SEND_SOUND(M, sound('sound/misc/notice1.ogg')) - else - SEND_SOUND(M, sound('sound/misc/notice2.ogg')) + if(!players) + players = GLOB.player_list + + for(var/mob/target in players) + if(isnewplayer(target)) + continue + if(!target.can_hear()) + continue + + var/complete_msg = "[title]
[message]

" + if(from) + complete_msg += "-[from]" + to_chat(target, complete_msg) + if(target.client.prefs.read_player_preference(/datum/preference/toggle/sound_announcements)) + var/sound_to_play = sound_override || (alert ? 'sound/misc/notice1.ogg' : 'sound/misc/notice2.ogg') + SEND_SOUND(target, sound(sound_to_play)) #undef DEFAULT_ALERT diff --git a/code/controllers/subsystem/nightshift.dm b/code/controllers/subsystem/nightshift.dm index e30561dca3d3d..e5cb73146c141 100644 --- a/code/controllers/subsystem/nightshift.dm +++ b/code/controllers/subsystem/nightshift.dm @@ -27,7 +27,7 @@ SUBSYSTEM_DEF(nightshift) priority_announce(message, sound='sound/misc/notice2.ogg', sender_override="Automated Lighting System Announcement") /datum/controller/subsystem/nightshift/proc/check_nightshift() - var/emergency = GLOB.security_level >= SEC_LEVEL_RED + var/emergency = SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED var/announcing = TRUE var/time = station_time() var/night_time = (time < nightshift_end_time) || (time > nightshift_start_time) diff --git a/code/controllers/subsystem/security_level.dm b/code/controllers/subsystem/security_level.dm new file mode 100644 index 0000000000000..2dfd91eaccbfb --- /dev/null +++ b/code/controllers/subsystem/security_level.dm @@ -0,0 +1,105 @@ +SUBSYSTEM_DEF(security_level) + name = "Security Level" + can_fire = FALSE // We will control when we fire in this subsystem + init_order = INIT_ORDER_SECURITY_LEVEL + /// Currently set security level + var/datum/security_level/current_security_level + /// A list of initialised security level datums. + var/list/available_levels = list() + +/datum/controller/subsystem/security_level/Initialize() + for(var/iterating_security_level_type in subtypesof(/datum/security_level)) + var/datum/security_level/new_security_level = new iterating_security_level_type + available_levels[new_security_level.name] = new_security_level + current_security_level = available_levels[number_level_to_text(SEC_LEVEL_GREEN)] + return SS_INIT_SUCCESS + +/datum/controller/subsystem/security_level/fire(resumed) + if(!current_security_level.looping_sound) // No sound? No play. + can_fire = FALSE + return + sound_to_playing_players(current_security_level.looping_sound) + + +/** + * Sets a new security level as our current level + * + * This is how everything should change the security level. + * + * Arguments: + * * new_level - The new security level that will become our current level + */ +/datum/controller/subsystem/security_level/proc/set_level(new_level) + new_level = istext(new_level) ? new_level : number_level_to_text(new_level) + if(new_level == current_security_level.name) // If we are already at the desired level, do nothing + return + + var/datum/security_level/selected_level = available_levels[new_level] + + if(!selected_level) + CRASH("set_level was called with an invalid security level([new_level])") + + if(SSnightshift.can_fire && (selected_level.number_level >= SEC_LEVEL_RED || current_security_level.number_level >= SEC_LEVEL_RED)) + SSnightshift.next_fire = world.time + 7 SECONDS // Fire nightshift after the security level announcement is complete + + announce_security_level(selected_level) // We want to announce BEFORE updating to the new level + + SSsecurity_level.current_security_level = selected_level + + if(selected_level.looping_sound) + wait = selected_level.looping_sound_interval + can_fire = TRUE + else + can_fire = FALSE + + if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) // By god this is absolutely shit + SSshuttle.emergency.alert_coeff_change(selected_level.shuttle_call_time_mod) + + SEND_SIGNAL(src, COMSIG_SECURITY_LEVEL_CHANGED, selected_level.number_level) + SSblackbox.record_feedback("tally", "security_level_changes", 1, selected_level.name) + +/** + * Handles announcements of the newly set security level + * + * Arguments: + * * selected_level - The new security level that has been set + */ +/datum/controller/subsystem/security_level/proc/announce_security_level(datum/security_level/selected_level) + if(selected_level.number_level > current_security_level.number_level) // We are elevating to this level. + minor_announce(selected_level.elevating_to_announcemnt, "Attention! Security level elevated to [selected_level.name]:", sound_override = selected_level.sound) + else // Going down + minor_announce(selected_level.lowering_to_announcement, "Attention! Security level lowered to [selected_level.name]:", sound_override = selected_level.sound) + +/** + * Returns the current security level as a number + */ +/datum/controller/subsystem/security_level/proc/get_current_level_as_number() + return ((!initialized || !current_security_level) ? SEC_LEVEL_GREEN : current_security_level.number_level) //Send the default security level in case the subsystem hasn't finished initializing yet + +/** + * Returns the current security level as text + */ +/datum/controller/subsystem/security_level/proc/get_current_level_as_text() + return ((!initialized || !current_security_level) ? "green" : current_security_level.name) + +/** + * Converts a text security level to a number + * + * Arguments: + * * level - The text security level to convert + */ +/datum/controller/subsystem/security_level/proc/text_level_to_number(text_level) + var/datum/security_level/selected_level = available_levels[text_level] + return selected_level?.number_level + +/** + * Converts a number security level to a text + * + * Arguments: + * * level - The number security level to convert + */ +/datum/controller/subsystem/security_level/proc/number_level_to_text(number_level) + for(var/iterating_level_text in available_levels) + var/datum/security_level/iterating_security_level = available_levels[iterating_level_text] + if(iterating_security_level.number_level == number_level) + return iterating_security_level.name diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 52529054d20e9..ec8fd7615daf2 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -141,8 +141,8 @@ SUBSYSTEM_DEF(shuttle) log_game("[msg] Alive: [alive], Roundstart: [total], Threshold: [threshold]") emergencyNoRecall = TRUE priority_announce("Catastrophic casualties detected: crisis shuttle protocols activated - jamming recall signals across all frequencies.", sound = SSstation.announcer.get_rand_alert_sound()) - if(emergency.timeLeft(1) > emergencyCallTime * 0.4) - emergency.request(null, set_coefficient = 0.4) + if(emergency.timeLeft(1) > emergencyCallTime * ALERT_COEFF_AUTOEVAC_CRITICAL) + emergency.request(null, set_coefficient = ALERT_COEFF_AUTOEVAC_CRITICAL) /datum/controller/subsystem/shuttle/proc/block_recall(lockout_timer) emergencyNoRecall = TRUE @@ -207,13 +207,13 @@ SUBSYSTEM_DEF(shuttle) call_reason = trim(html_encode(call_reason)) - if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH && seclevel2num(get_security_level()) > SEC_LEVEL_GREEN) + if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH && SSsecurity_level.get_current_level_as_number() > SEC_LEVEL_GREEN) to_chat(user, "You must provide a reason.") return var/area/signal_origin = get_area(user) var/emergency_reason = "\nNature of emergency:\n\n[call_reason]" - var/security_num = seclevel2num(get_security_level()) + var/security_num = SSsecurity_level.get_current_level_as_number() switch(security_num) if(SEC_LEVEL_RED,SEC_LEVEL_DELTA) emergency.request(null, signal_origin, html_decode(emergency_reason), 1) //There is a serious threat we gotta move no time to give them five minutes. @@ -275,7 +275,7 @@ SUBSYSTEM_DEF(shuttle) /datum/controller/subsystem/shuttle/proc/canRecall() if(!emergency || emergency.mode != SHUTTLE_CALL || emergencyNoRecall || SSticker.mode.name == "meteor") return - var/security_num = seclevel2num(get_security_level()) + var/security_num = SSsecurity_level.get_current_level_as_number() switch(security_num) if(SEC_LEVEL_GREEN) if(emergency.timeLeft(1) < emergencyCallTime) @@ -313,7 +313,7 @@ SUBSYSTEM_DEF(shuttle) if(callShuttle) if(EMERGENCY_IDLE_OR_RECALLED) - emergency.request(null, set_coefficient = 2.5) + emergency.request(null, set_coefficient = ALERT_COEFF_AUTOEVAC_NORMAL) log_game("There is no means of calling the shuttle anymore. Shuttle automatically called.") message_admins("All the communications consoles were destroyed and all AIs are inactive. Shuttle called.") diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm index d60ff575e9dc5..211054172d68c 100644 --- a/code/datums/world_topic.dm +++ b/code/datums/world_topic.dm @@ -242,7 +242,7 @@ data["map_name"] = SSmapping.config?.map_name || "Loading..." - data["security_level"] = get_security_level() + data["security_level"] = SSsecurity_level.get_current_level_as_text() data["round_duration"] = SSticker?.round_start_timeofday ? round((world.timeofday - SSticker.round_start_timeofday)/10) : 0 // Amount of world's ticks in seconds, useful for calculating round duration diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 4472654c9fb37..d49cf56acb87d 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -365,8 +365,8 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) print_command_report(., "Central Command Status Summary", announce=FALSE) priority_announce("A summary has been copied and printed to all communications consoles.", "Security level elevated.", ANNOUNCER_INTERCEPT) - if(GLOB.security_level < SEC_LEVEL_BLUE) - set_security_level(SEC_LEVEL_BLUE) + if(SSsecurity_level.get_current_level_as_number() < SEC_LEVEL_BLUE) + SSsecurity_level.set_level(SEC_LEVEL_BLUE) // Yes, this is copy pasted from game_mode /datum/game_mode/dynamic/check_finished(force_ending) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index dcf555e3bb7a8..7f03d165af976 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -396,8 +396,8 @@ print_command_report(intercepttext, "Central Command Status Summary", announce=FALSE) priority_announce("A summary has been copied and printed to all communications consoles.", "Enemy communication intercepted. Security level elevated.", ANNOUNCER_INTERCEPT) - if(GLOB.security_level < SEC_LEVEL_BLUE) - set_security_level(SEC_LEVEL_BLUE) + if(SSsecurity_level.get_current_level_as_number() < SEC_LEVEL_BLUE) + SSsecurity_level.set_level(SEC_LEVEL_BLUE) /* diff --git a/code/game/gamemodes/gangs/dominator.dm b/code/game/gamemodes/gangs/dominator.dm index 4af2519204b88..b1ecf4b1a2cc7 100644 --- a/code/game/gamemodes/gangs/dominator.dm +++ b/code/game/gamemodes/gangs/dominator.dm @@ -224,7 +224,7 @@ priority_announce("All hostile activity within station systems has ceased.","Network Alert", SSstation.announcer.get_rand_alert_sound()) if(get_security_level() == "delta") - set_security_level("red") + SSsecurity_level.set_level(SEC_LEVEL_RED) SSshuttle.clearHostileEnvironment(src) gang.message_gangtools("Hostile takeover cancelled: Dominator is no longer operational.[gang.dom_attempts ? " You have [gang.dom_attempts] attempt remaining." : " The station network will have likely blocked any more attempts by us."]",1,1) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 987db2e5a8f9e..1cf6eafd07f8c 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -124,13 +124,13 @@ playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) return - var/new_sec_level = seclevel2num(params["newSecurityLevel"]) + var/new_sec_level = SSsecurity_level.text_level_to_number(params["newSecurityLevel"]) if (new_sec_level != SEC_LEVEL_GREEN && new_sec_level != SEC_LEVEL_BLUE) return - if (GLOB.security_level == new_sec_level) + if (SSsecurity_level.get_current_level_as_number() == new_sec_level) return - set_security_level(new_sec_level) + SSsecurity_level.set_level(new_sec_level) to_chat(usr, "Authorization confirmed. Modifying security level.") playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) @@ -156,7 +156,7 @@ make_announcement(usr) . = TRUE if ("messageAssociates") - if (!authenticated(usr) || issilicon(usr) || (GLOB.security_level < SEC_LEVEL_RED && !authenticated_as_non_silicon_captain(usr))) + if (!authenticated(usr) || issilicon(usr) || (SSsecurity_level.get_current_level_as_number() < SEC_LEVEL_RED && !authenticated_as_non_silicon_captain(usr))) return if (!COOLDOWN_FINISHED(src, important_action_cooldown)) return @@ -351,7 +351,7 @@ //Main section is always visible when authenticated data["canBuyShuttles"] = can_buy_shuttles(user) data["canMakeAnnouncement"] = FALSE - data["canMessageAssociates"] = !issilicon(user) && GLOB.security_level >= SEC_LEVEL_RED + data["canMessageAssociates"] = !issilicon(user) && SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED data["canRecallShuttles"] = !issilicon(user) data["canRequestNuke"] = FALSE data["canSendToSectors"] = FALSE @@ -361,7 +361,7 @@ data["shuttleCalled"] = FALSE data["shuttleLastCalled"] = FALSE - data["alertLevel"] = get_security_level() + data["alertLevel"] = SSsecurity_level.get_current_level_as_text() data["authorizeName"] = authorize_name data["canLogOut"] = !issilicon(user) data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac(user) diff --git a/code/game/machinery/defibrillator_mount.dm b/code/game/machinery/defibrillator_mount.dm index 9870cc9615b5b..abfb524aa0587 100644 --- a/code/game/machinery/defibrillator_mount.dm +++ b/code/game/machinery/defibrillator_mount.dm @@ -44,7 +44,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount/loaded, 28) . = ..() if(defib) . += "There is a defib unit hooked up. Alt-click to remove it." - if(GLOB.security_level >= SEC_LEVEL_RED) + if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED) . += "Due to a security situation, its locking clamps can be toggled by swiping any ID." else . += "Its locking clamps can be [clamps_locked ? "dis" : ""]engaged by swiping an ID with access." @@ -103,7 +103,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount/loaded, 28) return var/obj/item/card/id = I.GetID() if(id) - if(check_access(id) || GLOB.security_level >= SEC_LEVEL_RED) //anyone can toggle the clamps in red alert! + if(check_access(id) || SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED) //anyone can toggle the clamps in red alert! if(!defib) to_chat(user, "You can't engage the clamps on a defibrillator that isn't there.") return diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 624edd84c1168..b303eb31cd972 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -42,20 +42,6 @@ var/unres_sides = 0 //Unrestricted sides. A bitflag for which direction (if any) can open the door with no access var/open_speed = 5 -/obj/machinery/door/examine(mob/user) - . = ..() - if(red_alert_access) - if(GLOB.security_level >= SEC_LEVEL_RED) - . += "Due to a security threat, its access requirements have been lifted!" - else - . += "In the event of a red alert, its access requirements will automatically lift." - . += "Its maintenance panel is screwed in place." - -/obj/machinery/door/check_access_list(list/access_list) - if(red_alert_access && GLOB.security_level >= SEC_LEVEL_RED) - return TRUE - return ..() - /obj/machinery/door/Initialize(mapload) . = ..() set_init_door_layer() @@ -68,15 +54,21 @@ //doors only block while dense though so we have to use the proc real_explosion_block = explosion_block explosion_block = EXPLOSION_BLOCK_PROC - if(red_alert_access) - RegisterSignal(SSdcs, COMSIG_GLOB_SECURITY_ALERT_CHANGE, PROC_REF(handle_alert)) + RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(check_security_level)) -/obj/machinery/door/proc/handle_alert(datum/source, new_alert) - SIGNAL_HANDLER - if(new_alert >= SEC_LEVEL_RED) - visible_message("[src] whirs as it automatically lifts access requirements!") - playsound(src, 'sound/machines/boltsup.ogg', 50, TRUE) +/obj/machinery/door/examine(mob/user) + . = ..() + if(red_alert_access) + if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED) + . += "Due to a security threat, its access requirements have been lifted!" + else + . += "In the event of a red alert, its access requirements will automatically lift." + . += "Its maintenance panel is screwed in place." +/obj/machinery/door/check_access_list(list/access_list) + if(red_alert_access && SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED) + return TRUE + return ..() /obj/machinery/door/proc/set_init_door_layer() if(density) @@ -426,3 +418,20 @@ /obj/machinery/door/GetExplosionBlock() return density ? real_explosion_block : 0 + +/** + * Signal handler for checking if we notify our surrounding that access requirements are lifted accordingly to a newly set security level + * + * Arguments: + * * source The datum source of the signal + * * new_level The new security level that is in effect + */ +/obj/machinery/door/proc/check_security_level(datum/source, new_level) + SIGNAL_HANDLER + + if(new_level <= SEC_LEVEL_BLUE) + return + if(!red_alert_access) + return + audible_message("[src] whirr[p_s()] as [p_they()] automatically lift[p_s()] access requirements!") + playsound(src, 'sound/machines/boltsup.ogg', 50, TRUE) diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index a8f5d048da866..70d46cfa00089 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -46,12 +46,7 @@ update_appearance() myarea = get_area(src) LAZYADD(myarea.firealarms, src) - RegisterSignal(SSdcs, COMSIG_GLOB_SECURITY_ALERT_CHANGE, PROC_REF(handle_alert)) - -/obj/machinery/firealarm/proc/handle_alert(datum/source, new_alert) - SIGNAL_HANDLER - if(is_station_level(z)) - update_appearance() + RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(check_security_level)) /obj/machinery/firealarm/Destroy() myarea.firereset(src) @@ -67,9 +62,9 @@ . += "fire_overlay" if(is_station_level(z)) - . += "fire_[GLOB.security_level]" - . += mutable_appearance(icon, "fire_[GLOB.security_level]") - . += emissive_appearance(icon, "fire_[GLOB.security_level]", layer, alpha = 255) + . += "fire_[SSsecurity_level.get_current_level_as_number()]" + . += mutable_appearance(icon, "fire_[SSsecurity_level.get_current_level_as_number()]") + . += emissive_appearance(icon, "fire_[SSsecurity_level.get_current_level_as_number()]", layer, alpha = 255) ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) else . += "fire_[SEC_LEVEL_GREEN]" @@ -120,6 +115,19 @@ alarm() ..() +/** + * Signal handler for checking if we should update fire alarm appearance accordingly to a newly set security level + * + * Arguments: + * * source The datum source of the signal + * * new_level The new security level that is in effect + */ +/obj/machinery/firealarm/proc/check_security_level(datum/source, new_level) + SIGNAL_HANDLER + + if(is_station_level(z)) + update_appearance() + /obj/machinery/firealarm/proc/alarm(mob/user) if(!is_operational || (last_alarm+FIREALARM_COOLDOWN > world.time)) return diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index 6678f8a7a8d52..a2d071256fd45 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -143,7 +143,7 @@ if(open) //You do not require access to close a case, only to open it. to_chat(user, "You close [src].") toggle_lock(user) - else if(security_level_locked > GLOB.security_level || !allowed(user)) + else if(security_level_locked > SSsecurity_level.get_current_level_as_number() || !allowed(user)) to_chat(user, "Access denied.") else to_chat(user, "You open [src].") diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index af25474593553..c77f6d58ce261 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -840,13 +840,16 @@ Traitors and the like can also be revived with the previous role mostly intact. if(!check_rights(R_ADMIN)) return - var/level = input("Select security level to change to","Set Security Level") as null|anything in list("green","blue","red","delta") - if(level) - set_security_level(level) + var/level = tgui_input_list(usr, "Select Security Level:", "Set Security Level", SSsecurity_level.available_levels) - log_admin("[key_name(usr)] changed the security level to [level]") - message_admins("[key_name_admin(usr)] changed the security level to [level]") - SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Security Level [capitalize(level)]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + if(!level) + return + + SSsecurity_level.set_level(level) + + log_admin("[key_name(usr)] changed the security level to [level]") + message_admins("[key_name_admin(usr)] changed the security level to [level]") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Security Level [capitalize(level)]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/toggle_nuke(obj/machinery/nuclearbomb/N in GLOB.nuke_list) set name = "Toggle Nuke" diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm index 792640428c5af..d5215bf517976 100644 --- a/code/modules/antagonists/blob/overmind.dm +++ b/code/modules/antagonists/blob/overmind.dm @@ -115,7 +115,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) else if(!victory_in_progress && (blobs_legit.len >= blobwincount)) victory_in_progress = TRUE priority_announce("Biohazard has reached critical mass. Station loss is imminent.", "Biohazard Alert", SSstation.announcer.get_rand_alert_sound()) - set_security_level("delta") + SSsecurity_level.set_level(SEC_LEVEL_DELTA) max_blob_points = INFINITY blob_points = INFINITY addtimer(CALLBACK(src, PROC_REF(victory)), 450) diff --git a/code/modules/antagonists/clock_cult/clockwork_massive.dm b/code/modules/antagonists/clock_cult/clockwork_massive.dm index 46c74b77669fa..aa19c1480fbce 100644 --- a/code/modules/antagonists/clock_cult/clockwork_massive.dm +++ b/code/modules/antagonists/clock_cult/clockwork_massive.dm @@ -88,7 +88,7 @@ GLOBAL_LIST_INIT(clockwork_portals, list()) for(var/obj/effect/portal/wormhole/clockcult/CC in GLOB.all_wormholes) qdel(CC) SSshuttle.clearHostileEnvironment(src) - set_security_level(SEC_LEVEL_RED) + SSsecurity_level.set_level(SEC_LEVEL_RED) addtimer(CALLBACK(src, PROC_REF(clockies_win)), 300) /obj/structure/destructible/clockwork/massive/celestial_gateway/proc/clockies_win() @@ -134,7 +134,7 @@ GLOBAL_LIST_INIT(clockwork_portals, list()) /obj/structure/destructible/clockwork/massive/celestial_gateway/proc/announce_gateway() set_dynamic_high_impact_event("clockwork ark has opened") activated = TRUE - set_security_level(SEC_LEVEL_DELTA) + SSsecurity_level.set_level(SEC_LEVEL_DELTA) mass_recall(TRUE) var/grace_time = GLOB.narsie_breaching ? 0 : 1800 addtimer(CALLBACK(src, PROC_REF(begin_assault)), grace_time) diff --git a/code/modules/antagonists/clock_cult/helpers/clockcult_ending.dm b/code/modules/antagonists/clock_cult/helpers/clockcult_ending.dm index de51ca0ba2f06..6085f97b93802 100644 --- a/code/modules/antagonists/clock_cult/helpers/clockcult_ending.dm +++ b/code/modules/antagonists/clock_cult/helpers/clockcult_ending.dm @@ -1,7 +1,7 @@ /proc/trigger_clockcult_victory(hostile) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(clockcult_gg)), 700) sleep(50) - set_security_level("delta") + SSsecurity_level.set_level(SEC_LEVEL_DELTA) priority_announce("Huge gravitational-energy spike detected emminating from a neutron star near your sector. Event has been determined to be survivable by 0% of life. ESTIMATED TIME UNTIL ENERGY PULSE REACHES [GLOB.station_name]: 56 SECONDS. Godspeed crew, glory to Nanotrasen. -Admiral Telvig.", "Central Command Anomolous Materials Division", 'sound/misc/bloblarm.ogg') for(var/client/C in GLOB.clients) SEND_SOUND(C, sound('sound/misc/airraid.ogg', 1)) diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index ad574f51bf3d4..b4e2230551530 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -324,7 +324,7 @@ Striking a noncultist, however, will tear their flesh."} if(SSshuttle.emergency.mode == SHUTTLE_CALL) var/cursetime = 1800 var/timer = SSshuttle.emergency.timeLeft(1) + cursetime - var/security_num = seclevel2num(get_security_level()) + var/security_num = SSsecurity_level.get_current_level_as_number() var/set_coefficient = 1 switch(security_num) if(SEC_LEVEL_GREEN) diff --git a/code/modules/antagonists/cult/narsie.dm b/code/modules/antagonists/cult/narsie.dm index 3fd0470a5fd2d..73a3102022e85 100644 --- a/code/modules/antagonists/cult/narsie.dm +++ b/code/modules/antagonists/cult/narsie.dm @@ -206,7 +206,7 @@ sleep(500) priority_announce("Simulations on acausal dimensional event complete. Deploying solution package now. Deployment ETA: ONE MINUTE. ", "Central Command Higher Dimensional Affairs", SSstation.announcer.get_rand_alert_sound()) sleep(50) - set_security_level("delta") + SSsecurity_level.set_level(SEC_LEVEL_DELTA) SSshuttle.registerHostileEnvironment(src) sleep(600) if(resolved == FALSE) diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index 4f65c750f2b65..1da124706b09f 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -46,7 +46,7 @@ STOP_PROCESSING(SSobj, core) update_icon() AddElement(/datum/element/point_of_interest) - previous_level = get_security_level() + previous_level = SSsecurity_level.get_current_level_as_text() /obj/machinery/nuclearbomb/Destroy() safety = FALSE @@ -427,7 +427,7 @@ safety = !safety if(safety) if(timing) - set_security_level(previous_level) + SSsecurity_level.set_level(previous_level) stop_soundtrack_music(stop_playing = TRUE) for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list) S.switch_mode_to(initial(S.mode)) @@ -443,12 +443,12 @@ return timing = !timing if(timing) - previous_level = get_security_level() + previous_level = SSsecurity_level.get_current_level_as_number() detonation_timer = world.time + (timer_set * 10) for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list) S.switch_mode_to(TRACK_INFILTRATOR) countdown.start() - set_security_level(SEC_LEVEL_DELTA) + SSsecurity_level.set_level(SEC_LEVEL_DELTA) if (proper_bomb) // Why does this exist set_dynamic_high_impact_event("nuclear bomb has been armed") @@ -456,7 +456,7 @@ else detonation_timer = null - set_security_level(previous_level) + SSsecurity_level.set_level(previous_level) stop_soundtrack_music(stop_playing = TRUE) for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list) @@ -585,7 +585,7 @@ detonation_timer = null exploding = FALSE exploded = TRUE - set_security_level(previous_level) + SSsecurity_level.set_level(previous_level) for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list) S.switch_mode_to(initial(S.mode)) S.alert = FALSE diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm index bbc744eae9834..c9a15ce60686e 100644 --- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm +++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm @@ -326,7 +326,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list( if(!owner || QDELETED(owner)) return priority_announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", ANNOUNCER_AIMALF) - set_security_level("delta") + SSsecurity_level.set_level(SEC_LEVEL_DELTA) owner.log_message("activated malf module [name]", LOG_GAME) var/obj/machinery/doomsday_device/DOOM = new(owner_AI) owner_AI.nuking = TRUE diff --git a/code/modules/events/asteroid_impact.dm b/code/modules/events/asteroid_impact.dm index 0db2eb2892264..a303576af65c3 100644 --- a/code/modules/events/asteroid_impact.dm +++ b/code/modules/events/asteroid_impact.dm @@ -13,7 +13,7 @@ /datum/round_event/asteroid_impact/announce(fake) priority_announce("A class-A asteroid has been detected on a collision course with the station. Destruction of the station is innevitable.", SSstation.announcer.get_rand_alert_sound()) if(!fake) - set_security_level(SEC_LEVEL_DELTA) + SSsecurity_level.set_level(SEC_LEVEL_DELTA) var/area/A = GLOB.areas_by_type[/area/centcom] if(EMERGENCY_IDLE_OR_RECALLED) SSshuttle.emergency.request(null, A, "Automatic Shuttle Call: Station destruction imminent.", TRUE) diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index fa4346abb58f0..a9b65598d65e3 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -46,7 +46,7 @@ /mob/living/silicon/ai/proc/ShutOffDoomsdayDevice() if(nuking) - set_security_level("red") + SSsecurity_level.set_level(SEC_LEVEL_RED) nuking = FALSE for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list) P.switch_mode_to(TRACK_NUKE_DISK) //Party's over, back to work, everyone diff --git a/code/modules/mob/mob_stat.dm b/code/modules/mob/mob_stat.dm index c9200140700a5..73e365a2620fd 100644 --- a/code/modules/mob/mob_stat.dm +++ b/code/modules/mob/mob_stat.dm @@ -238,7 +238,7 @@ else tab_data["Players Playing/Connected"] = GENERATE_STAT_TEXT("[get_active_player_count()]/[GLOB.clients.len]") if(SSticker.round_start_time) - tab_data["Security Level"] = GENERATE_STAT_TEXT("[capitalize(get_security_level())]") + tab_data["Security Level"] = GENERATE_STAT_TEXT("[capitalize(SSsecurity_level.get_current_level_as_text())]") tab_data["divider_3"] = GENERATE_STAT_DIVIDER if(SSshuttle.emergency) diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm index a0627309447f7..89c92e3f140e6 100644 --- a/code/modules/security_levels/keycard_authentication.dm +++ b/code/modules/security_levels/keycard_authentication.dm @@ -51,7 +51,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26) var/list/data = list() data["waiting"] = waiting data["auth_required"] = event_source ? event_source.event : 0 - data["red_alert"] = (seclevel2num(get_security_level()) >= SEC_LEVEL_RED) ? 1 : 0 + data["red_alert"] = (SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED) ? 1 : 0 data["emergency_maint"] = GLOB.emergency_access data["bsa_unlock"] = GLOB.bsa_unlock return data @@ -134,7 +134,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26) deadchat_broadcast("[confirmer] confirmed [event] at [A2.name].", confirmer) switch(event) if(KEYCARD_RED_ALERT) - set_security_level(SEC_LEVEL_RED) + SSsecurity_level.set_level(SEC_LEVEL_RED) if(KEYCARD_EMERGENCY_MAINTENANCE_ACCESS) make_maint_all_access() if(KEYCARD_BSA_UNLOCK) diff --git a/code/modules/security_levels/security_level_datums.dm b/code/modules/security_levels/security_level_datums.dm new file mode 100644 index 0000000000000..4737e21e41d0d --- /dev/null +++ b/code/modules/security_levels/security_level_datums.dm @@ -0,0 +1,86 @@ +/** + * Security levels + * + * These are used by the security level subsystem. Each one of these represents a security level that a player can set. + * + * Base type is abstract + */ + +/datum/security_level + /// The name of this security level. + var/name = "not set" + /// The numerical level of this security level, see defines for more information. + var/number_level = -1 + /// The sound that we will play when this security level is set + var/sound + /// The looping sound that will be played while the security level is set + var/looping_sound + /// The looping sound interval + var/looping_sound_interval + /// The shuttle call time modification of this security level + var/shuttle_call_time_mod = 0 + /// Our announcement when lowering to this level + var/lowering_to_announcement + /// Our announcement when elevating to this level + var/elevating_to_announcemnt + /// Our configuration key for lowering to text, if set, will override the default lowering to announcement. + var/lowering_to_configuration_key + /// Our configuration key for elevating to text, if set, will override the default elevating to announcement. + var/elevating_to_configuration_key + +/datum/security_level/New() + . = ..() + if(lowering_to_configuration_key) // I'm not sure about you, but isn't there an easier way to do this? + lowering_to_announcement = global.config.Get(lowering_to_configuration_key) + if(elevating_to_configuration_key) + elevating_to_announcemnt = global.config.Get(elevating_to_configuration_key) + +/** + * GREEN + * + * No threats + */ +/datum/security_level/green + name = "green" + sound = 'sound/misc/notice2.ogg' // Friendly beep + number_level = SEC_LEVEL_GREEN + lowering_to_configuration_key = /datum/config_entry/string/alert_green + shuttle_call_time_mod = ALERT_COEFF_GREEN + +/** + * BLUE + * + * Caution advised + */ +/datum/security_level/blue + name = "blue" + sound = 'sound/misc/notice1.ogg' // Angry alarm + number_level = SEC_LEVEL_BLUE + lowering_to_configuration_key = /datum/config_entry/string/alert_blue_downto + elevating_to_configuration_key = /datum/config_entry/string/alert_blue_upto + shuttle_call_time_mod = ALERT_COEFF_BLUE + +/** + * RED + * + * Hostile threats + */ +/datum/security_level/red + name = "red" + sound = 'sound/misc/notice1.ogg' // The same angry alarm + number_level = SEC_LEVEL_RED + lowering_to_configuration_key = /datum/config_entry/string/alert_red_downto + elevating_to_configuration_key = /datum/config_entry/string/alert_red_upto + shuttle_call_time_mod = ALERT_COEFF_RED + +/** + * DELTA + * + * Station destruction is imminent + */ +/datum/security_level/delta + name = "delta" + sound = 'sound/misc/notice1.ogg' // The same angry alarm, again + number_level = SEC_LEVEL_DELTA + elevating_to_configuration_key = /datum/config_entry/string/alert_delta + shuttle_call_time_mod = ALERT_COEFF_DELTA diff --git a/code/modules/security_levels/security_levels.dm b/code/modules/security_levels/security_levels.dm deleted file mode 100644 index 95398906c4da7..0000000000000 --- a/code/modules/security_levels/security_levels.dm +++ /dev/null @@ -1,97 +0,0 @@ -GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN) -//SEC_LEVEL_GREEN = code green -//SEC_LEVEL_BLUE = code blue -//SEC_LEVEL_RED = code red -//SEC_LEVEL_DELTA = code delta - -//config.alert_desc_blue_downto - -/proc/set_security_level(level) - switch(level) - if("green") - level = SEC_LEVEL_GREEN - if("blue") - level = SEC_LEVEL_BLUE - if("red") - level = SEC_LEVEL_RED - if("delta") - level = SEC_LEVEL_DELTA - - //Will not be announced if you try to set to the same level as it already is - if(level < SEC_LEVEL_GREEN || level > SEC_LEVEL_DELTA || level == GLOB.security_level) - return - switch(level) - if(SEC_LEVEL_GREEN) - minor_announce(CONFIG_GET(string/alert_green), "Attention! Security level lowered to green:") - if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - if(GLOB.security_level >= SEC_LEVEL_RED) - SSshuttle.emergency.modTimer(4) - else - SSshuttle.emergency.modTimer(2) - - if(SEC_LEVEL_BLUE) - if(GLOB.security_level < SEC_LEVEL_BLUE) - minor_announce(CONFIG_GET(string/alert_blue_upto), "Attention! Security level elevated to blue:",1) - if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - SSshuttle.emergency.modTimer(0.5) - else - minor_announce(CONFIG_GET(string/alert_blue_downto), "Attention! Security level lowered to blue:") - if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - SSshuttle.emergency.modTimer(2) - - if(SEC_LEVEL_RED) - if(GLOB.security_level < SEC_LEVEL_RED) - minor_announce(CONFIG_GET(string/alert_red_upto), "Attention! Code red!",1) - if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - if(GLOB.security_level == SEC_LEVEL_GREEN) - SSshuttle.emergency.modTimer(0.25) - else - SSshuttle.emergency.modTimer(0.5) - else - minor_announce(CONFIG_GET(string/alert_red_downto), "Attention! Code red!") - - if(SEC_LEVEL_DELTA) - minor_announce(CONFIG_GET(string/alert_delta), "Attention! Delta security level reached!",1) - if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - if(GLOB.security_level == SEC_LEVEL_GREEN) - SSshuttle.emergency.modTimer(0.25) - else if(GLOB.security_level == SEC_LEVEL_BLUE) - SSshuttle.emergency.modTimer(0.5) - - GLOB.security_level = level - SEND_GLOBAL_SIGNAL(COMSIG_GLOB_SECURITY_ALERT_CHANGE, level) - SSblackbox.record_feedback("tally", "security_level_changes", 1, get_security_level()) - SSnightshift.check_nightshift() - -/proc/get_security_level() - switch(GLOB.security_level) - if(SEC_LEVEL_GREEN) - return "green" - if(SEC_LEVEL_BLUE) - return "blue" - if(SEC_LEVEL_RED) - return "red" - if(SEC_LEVEL_DELTA) - return "delta" - -/proc/num2seclevel(num) - switch(num) - if(SEC_LEVEL_GREEN) - return "green" - if(SEC_LEVEL_BLUE) - return "blue" - if(SEC_LEVEL_RED) - return "red" - if(SEC_LEVEL_DELTA) - return "delta" - -/proc/seclevel2num(seclevel) - switch( lowertext(seclevel) ) - if("green") - return SEC_LEVEL_GREEN - if("blue") - return SEC_LEVEL_BLUE - if("red") - return SEC_LEVEL_RED - if("delta") - return SEC_LEVEL_DELTA diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 495a6bd7bc033..780b3787047fc 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -320,16 +320,10 @@ . = ..() /obj/docking_port/mobile/emergency/request(obj/docking_port/stationary/S, area/signalOrigin, reason, redAlert, set_coefficient=null) - if(!isnum_safe(set_coefficient)) - var/security_num = seclevel2num(get_security_level()) - switch(security_num) - if(SEC_LEVEL_GREEN) - set_coefficient = 2 - if(SEC_LEVEL_BLUE) - set_coefficient = 1 - else - set_coefficient = 0.5 - var/call_time = SSshuttle.emergencyCallTime * set_coefficient * engine_coeff + if(!isnum(set_coefficient)) + set_coefficient = SSsecurity_level.current_security_level.shuttle_call_time_mod + alert_coeff = set_coefficient + var/call_time = SSshuttle.emergencyCallTime * alert_coeff * engine_coeff switch(mode) // The shuttle can not normally be called while "recalling", so // if this proc is called, it's via admin fiat @@ -587,7 +581,7 @@ var/obj/machinery/computer/shuttle_flight/C = getControlConsole() if(!istype(C, /obj/machinery/computer/shuttle_flight/pod)) return ..() - if(GLOB.security_level >= SEC_LEVEL_RED || (C && (C.obj_flags & EMAGGED))) + if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED || (C && (C.obj_flags & EMAGGED))) if(launch_status == UNLAUNCHED) launch_status = EARLY_LAUNCHED return ..() @@ -619,11 +613,7 @@ /obj/machinery/computer/shuttle_flight/pod/Initialize() . = ..() - RegisterSignal(SSdcs, COMSIG_GLOB_SECURITY_ALERT_CHANGE, PROC_REF(handle_alert)) - -/obj/machinery/computer/shuttle_flight/pod/proc/handle_alert(datum/source, new_alert) - SIGNAL_HANDLER - admin_controlled = (new_alert < SEC_LEVEL_RED) // admin_controlled is FALSE if its red or delta + RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(check_lock)) /obj/machinery/computer/shuttle_flight/pod/update_icon() return @@ -637,6 +627,20 @@ if(recall_docking_port_id == initial(recall_docking_port_id) || override) recall_docking_port_id = "pod_lavaland[idnum]" +/** + * Signal handler for checking if we should lock or unlock escape pods accordingly to a newly set security level + * + * Arguments: + * * source The datum source of the signal + * * new_level The new security level that is in effect + */ +/obj/machinery/computer/shuttle_flight/pod/proc/check_lock(datum/source, new_level) + SIGNAL_HANDLER + + if(obj_flags & EMAGGED) + return + admin_controlled = (new_level < SEC_LEVEL_RED) + /obj/docking_port/stationary/random name = "escape pod" id = "pod" @@ -728,7 +732,7 @@ /obj/item/storage/pod/can_interact(mob/user) if(!..()) return FALSE - if(GLOB.security_level >= SEC_LEVEL_RED || unlocked) + if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED || unlocked) return TRUE to_chat(user, "The storage unit will only unlock during a Red or Delta security alert.") diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 1bbfc0f1b3025..a8461d69d042d 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -309,6 +309,8 @@ GLOBAL_LIST_INIT(shuttle_turf_blacklist, typecacheof(list( var/list/shuttle_areas + ///Speed multiplier based on station alert level + var/alert_coeff = ALERT_COEFF_BLUE ///used as a timer (if you want time left to complete move, use timeLeft proc) var/timer var/last_timer_length @@ -939,6 +941,20 @@ GLOBAL_LIST_INIT(shuttle_turf_blacklist, typecacheof(list( last_timer_length *= multiple setTimer(time_remaining) +/obj/docking_port/mobile/proc/alert_coeff_change(new_coeff) + if(isnull(new_coeff)) + return + + var/time_multiplier = new_coeff / alert_coeff + var/time_remaining = timer - world.time + if(time_remaining < 0 || !last_timer_length) + return + + time_remaining *= time_multiplier + last_timer_length *= time_multiplier + alert_coeff = new_coeff + setTimer(time_remaining) + /obj/docking_port/mobile/proc/invertTimer() if(!last_timer_length) return diff --git a/code/modules/unit_tests/security_levels.dm b/code/modules/unit_tests/security_levels.dm new file mode 100644 index 0000000000000..eecef51ff99c9 --- /dev/null +++ b/code/modules/unit_tests/security_levels.dm @@ -0,0 +1,16 @@ +/** + * Security Level Unit Test + * + * This test is here to ensure there are no security levels with the same name or number level. Having the same name or number level will cause problems. + */ +/datum/unit_test/security_levels + +/datum/unit_test/security_levels/Run() + var/list/comparison = subtypesof(/datum/security_level) + + for(var/datum/security_level/iterating_level in comparison) + for(var/datum/security_level/iterating_level_check in comparison) + if(iterating_level == iterating_level_check) // If they are the same type, don't check + continue + TEST_ASSERT_NOTEQUAL(iterating_level.name, iterating_level_check.name, "Security level [iterating_level] has the same name as [iterating_level_check]!") + TEST_ASSERT_NOTEQUAL(iterating_level.number_level, iterating_level_check.number_level, "Security level [iterating_level] has the same level number as [iterating_level_check]!")