diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index 2f9617e7203..b5c62ae9056 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -31,6 +31,11 @@
///from SSsun when the sun changes position : (azimuth)
#define COMSIG_SUN_MOVED "sun_moved"
+///from SSsecurity_level on planning security level change : (previous_level_number, new_level_number)
+#define COMSIG_SECURITY_LEVEL_CHANGE_PLANNED "security_level_change_planned"
+///from SSsecurity_level when the security level changes : (previous_level_number, new_level_number)
+#define COMSIG_SECURITY_LEVEL_CHANGED "security_level_changed"
+
//////////////////////////////////////////////////////////////////
// /datum signals
diff --git a/code/controllers/subsystem/SSnightshift.dm b/code/controllers/subsystem/SSnightshift.dm
index 446158b9805..49df5c617e5 100644
--- a/code/controllers/subsystem/SSnightshift.dm
+++ b/code/controllers/subsystem/SSnightshift.dm
@@ -31,7 +31,7 @@ SUBSYSTEM_DEF(nightshift)
/datum/controller/subsystem/nightshift/proc/check_nightshift(check_canfire=FALSE)
if(check_canfire && !can_fire)
return
- 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/SSsecurity_level.dm b/code/controllers/subsystem/SSsecurity_level.dm
new file mode 100644
index 00000000000..b1e66f866e7
--- /dev/null
+++ b/code/controllers/subsystem/SSsecurity_level.dm
@@ -0,0 +1,158 @@
+#define DEFAULT_SECURITY_LEVEL_NUMBER SEC_LEVEL_GREEN
+#define DEFAULT_SECURITY_LEVEL_NAME "green"
+
+GLOBAL_DATUM_INIT(security_announcement, /datum/announcer, new(config_type = /datum/announcement_configuration/security))
+
+SUBSYSTEM_DEF(security_level)
+ name = "Security Level"
+ flags = SS_NO_FIRE
+ /// Option reference of a timer id of the latest set security level. Only set when security level is changed to one with `set_delay` > 0
+ var/security_level_set_timer_id
+ /// 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()
+ if (!length(available_levels))
+ for(var/security_level_type in subtypesof(/datum/security_level))
+ var/datum/security_level/new_security_level = new security_level_type
+ available_levels[new_security_level.name] = new_security_level
+
+ if (!current_security_level)
+ current_security_level = available_levels[number_level_to_text(DEFAULT_SECURITY_LEVEL_NUMBER)]
+
+/datum/controller/subsystem/security_level/Recover()
+ security_level_set_timer_id = SSsecurity_level.security_level_set_timer_id
+ current_security_level = SSsecurity_level.current_security_level
+ available_levels = SSsecurity_level.available_levels
+
+/**
+ * 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, could be number or name of security level
+ */
+/datum/controller/subsystem/security_level/proc/set_level(new_level)
+ var/new_level_name = istext(new_level) ? new_level : number_level_to_text(new_level)
+ if(new_level_name == current_security_level.name)
+ return
+
+ var/datum/security_level/selected_level = available_levels[new_level_name]
+
+ if(!selected_level)
+ CRASH("set_level was called with an invalid security level([new_level_name])")
+
+ if(security_level_set_timer_id)
+ deltimer(security_level_set_timer_id)
+ security_level_set_timer_id = null
+
+ pre_set_level(selected_level)
+
+ if(selected_level.set_delay > 0)
+ SEND_SIGNAL(src, COMSIG_SECURITY_LEVEL_CHANGE_PLANNED, current_security_level.number_level, selected_level.number_level)
+ security_level_set_timer_id = addtimer(CALLBACK(src, PROC_REF(do_set_level), selected_level), selected_level.set_delay, TIMER_UNIQUE | TIMER_STOPPABLE)
+ else
+ do_set_level(selected_level)
+
+/**
+ * Do things before the actual security level set, like executing security level specific pre change behavior
+ *
+ * Arguments:
+ * * selected_level - The datum of security level selected to be changed to
+ */
+/datum/controller/subsystem/security_level/proc/pre_set_level(datum/security_level/selected_level)
+ PRIVATE_PROC(TRUE)
+
+ selected_level.pre_change()
+
+/**
+ * Actually sets the security level after the announcement
+ *
+ * Sends `COMSIG_SECURITY_LEVEL_CHANGED` in the end
+ *
+ * Arguments:
+ * * selected_level - The datum of security level selected to be changed to
+ */
+/datum/controller/subsystem/security_level/proc/do_set_level(datum/security_level/selected_level)
+ PRIVATE_PROC(TRUE)
+
+ var/datum/security_level/previous_security_level = current_security_level
+ if(previous_security_level.number_level < SEC_LEVEL_RED && selected_level.number_level >= SEC_LEVEL_RED)
+ // Mark down this time to prevent shuttle cheese
+ SSshuttle.emergency_sec_level_time = world.time
+
+ announce_security_level(selected_level)
+ current_security_level = selected_level
+
+ post_status(current_security_level.status_display_mode, current_security_level.status_display_data)
+ SSnightshift.check_nightshift()
+ SSblackbox.record_feedback("tally", "security_level_changes", 1, selected_level.name)
+
+ SEND_SIGNAL(src, COMSIG_SECURITY_LEVEL_CHANGED, previous_security_level.number_level, selected_level.number_level)
+
+/**
+ * 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)
+ GLOB.security_announcement.Announce(
+ selected_level.elevating_to_announcement_text,
+ selected_level.elevating_to_announcement_title,
+ new_sound = selected_level.elevating_to_sound,
+ new_sound2 = selected_level.ai_announcement_sound)
+ else
+ GLOB.security_announcement.Announce(
+ selected_level.lowering_to_announcement_text,
+ selected_level.lowering_to_announcement_title,
+ new_sound = selected_level.lowering_to_sound,
+ new_sound2 = selected_level.ai_announcement_sound)
+
+/**
+ * Returns the current security level as a number
+ * In case the subsystem hasn't finished initializing yet, returns default security level
+ */
+/datum/controller/subsystem/security_level/proc/get_current_level_as_number()
+ return ((!initialized || !current_security_level) ? DEFAULT_SECURITY_LEVEL_NUMBER : current_security_level.number_level)
+
+/**
+ * Returns the current security level as text
+ */
+/datum/controller/subsystem/security_level/proc/get_current_level_as_text()
+ return ((!initialized || !current_security_level) ? DEFAULT_SECURITY_LEVEL_NAME : 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/level_text in available_levels)
+ var/datum/security_level/security_level = available_levels[level_text]
+ if(security_level.number_level == number_level)
+ return security_level.name
+
+/**
+ * Returns security level name formatted with it's color
+ */
+/datum/controller/subsystem/security_level/proc/get_colored_current_security_level_name()
+ return "[current_security_level.name]"
+
+#undef DEFAULT_SECURITY_LEVEL_NUMBER
+#undef DEFAULT_SECURITY_LEVEL_NAME
diff --git a/code/controllers/subsystem/SSshuttles.dm b/code/controllers/subsystem/SSshuttles.dm
index 003e49309ca..3320c1b294b 100644
--- a/code/controllers/subsystem/SSshuttles.dm
+++ b/code/controllers/subsystem/SSshuttles.dm
@@ -118,7 +118,7 @@ SUBSYSTEM_DEF(shuttle)
var/area/signal_origin = get_area(user)
var/emergency_reason = "\nNature of emergency:\n\n[call_reason]"
- if(seclevel2num(get_security_level()) >= SEC_LEVEL_RED) // There is a serious threat we gotta move no time to give them five minutes.
+ if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED) // There is a serious threat we gotta move no time to give them five minutes.
var/extra_minutes = 0
var/priority_time = emergencyCallTime * 0.5
if(world.time - emergency_sec_level_time < priority_time)
@@ -152,7 +152,7 @@ SUBSYSTEM_DEF(shuttle)
return
if(!emergency.canRecall)
return
- if(seclevel2num(get_security_level()) >= SEC_LEVEL_RED)
+ if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED)
if(emergency.timeLeft(1) < emergencyCallTime * 0.25)
return
else
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 18118b7dbf9..4fe169e79ae 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -85,6 +85,9 @@
/area/Initialize(mapload)
+ if(is_station_level(z))
+ RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(on_security_level_update))
+
GLOB.all_areas += src
icon_state = ""
layer = AREA_LAYER
@@ -116,6 +119,11 @@
return INITIALIZE_HINT_LATELOAD
+/area/proc/on_security_level_update(datum/source, previous_level_number, new_level_number)
+ SIGNAL_HANDLER
+
+ area_emergency_mode = (new_level_number >= SEC_LEVEL_EPSILON)
+
/area/proc/create_powernet()
powernet = new()
powernet.powernet_area = src
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index 8d40d27b4c9..2b16ceba62a 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -241,7 +241,7 @@
/datum/action/innate/ai/nuke_station/proc/set_us_up_the_bomb()
to_chat(owner_AI, "Nuclear device armed.")
GLOB.major_announcement.Announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", 'sound/AI/aimalf.ogg')
- set_security_level("delta")
+ SSsecurity_level.set_level(SEC_LEVEL_DELTA)
owner_AI.nuking = TRUE
var/obj/machinery/doomsday_device/DOOM = new /obj/machinery/doomsday_device(owner_AI)
owner_AI.doomsday_device = DOOM
diff --git a/code/game/gamemodes/nuclear/nuclear_challenge.dm b/code/game/gamemodes/nuclear/nuclear_challenge.dm
index cd17a0c252c..0cc132b2abd 100644
--- a/code/game/gamemodes/nuclear/nuclear_challenge.dm
+++ b/code/game/gamemodes/nuclear/nuclear_challenge.dm
@@ -49,7 +49,7 @@
return
GLOB.major_announcement.Announce(war_declaration, "Declaration of War", 'sound/effects/siren.ogg', msg_sanitized = TRUE)
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(set_security_level), SEC_LEVEL_GAMMA), 30 SECONDS)
+ addtimer(CALLBACK(SSsecurity_level, TYPE_PROC_REF(/datum/controller/subsystem/security_level, set_level), SEC_LEVEL_GAMMA), 30 SECONDS)
to_chat(user, "You've attracted the attention of powerful forces within the syndicate. A bonus bundle of telecrystals has been granted to your team. Great things await you if you complete the mission.")
to_chat(user, "Your bonus telecrystals have been split between your team's uplinks.")
diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index 36f7db9e97b..8720f8b98ed 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -69,7 +69,7 @@ GLOBAL_VAR(bomb_set)
r_code = rand(10000, 99999) // Creates a random code upon object spawn.
wires = new/datum/wires/nuclearbomb(src)
ADD_TRAIT(src, TRAIT_OBSCURED_WIRES, ROUNDSTART_TRAIT)
- previous_level = get_security_level()
+ previous_level = SSsecurity_level.get_current_level_as_text()
GLOB.poi_list |= src
core = new /obj/item/nuke_core/plutonium(src)
STOP_PROCESSING(SSobj, core) //Let us not irradiate the vault by default.
@@ -480,7 +480,7 @@ GLOBAL_VAR(bomb_set)
safety = !(safety)
if(safety)
if(!is_syndicate)
- set_security_level(previous_level)
+ SSsecurity_level.set_level(previous_level)
timing = FALSE
GLOB.bomb_set = FALSE
if("toggle_armed")
@@ -498,13 +498,13 @@ GLOBAL_VAR(bomb_set)
if(!safety)
message_admins("[key_name_admin(usr)] engaged a nuclear bomb [ADMIN_JMP(src)]")
if(!is_syndicate)
- set_security_level("delta")
+ SSsecurity_level.set_level(SEC_LEVEL_DELTA)
GLOB.bomb_set = TRUE // There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke
else
GLOB.bomb_set = TRUE
else
if(!is_syndicate)
- set_security_level(previous_level)
+ SSsecurity_level.set_level(previous_level)
GLOB.bomb_set = FALSE
if(!lighthack)
icon_state = "nuclearbomb1"
@@ -608,7 +608,7 @@ GLOBAL_VAR(bomb_set)
safety = !safety
if(safety == 1)
if(!is_syndicate)
- set_security_level(previous_level)
+ SSsecurity_level.set_level(previous_level)
visible_message("[src] quiets down.")
if(!lighthack)
if(icon_state == "nuclearbomb2")
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index d121a0628c4..6d36eca12d2 100644
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -61,15 +61,15 @@
/obj/machinery/computer/communications/proc/change_security_level(new_level)
tmp_alertlevel = new_level
- var/old_level = GLOB.security_level
+ var/old_level = SSsecurity_level.get_current_level_as_number()
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) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this
- set_security_level(tmp_alertlevel)
- if(GLOB.security_level != old_level)
+ SSsecurity_level.set_level(tmp_alertlevel)
+ if(SSsecurity_level.get_current_level_as_number() != old_level)
//Only notify the admins if an actual change happened
- log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
- message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
+ log_game("[key_name(usr)] has changed the security level to [SSsecurity_level.get_current_level_as_text()].")
+ message_admins("[key_name_admin(usr)] has changed the security level to [SSsecurity_level.get_current_level_as_text()].")
tmp_alertlevel = 0
/obj/machinery/computer/communications/ui_act(action, params)
@@ -132,7 +132,7 @@
var/obj/item/card/id/I = H.get_idcard(TRUE)
if(istype(I))
// You must have captain access and it must be red alert or lower (no getting off delta/epsilon)
- if((ACCESS_CAPTAIN in I.access) && GLOB.security_level <= SEC_LEVEL_RED)
+ if((ACCESS_CAPTAIN in I.access) && SSsecurity_level.get_current_level_as_number() <= SEC_LEVEL_RED)
change_security_level(text2num(params["level"]))
else
to_chat(usr, "You are not authorized to do this.")
@@ -355,8 +355,8 @@
)
)
- data["security_level"] = GLOB.security_level
- switch(GLOB.security_level)
+ data["security_level"] = SSsecurity_level.get_current_level_as_number()
+ switch(SSsecurity_level.get_current_level_as_number())
if(SEC_LEVEL_GREEN)
data["security_level_color"] = "green";
if(SEC_LEVEL_BLUE)
@@ -365,7 +365,7 @@
data["security_level_color"] = "red";
else
data["security_level_color"] = "purple";
- data["str_security_level"] = capitalize(get_security_level())
+ data["str_security_level"] = capitalize(SSsecurity_level.get_current_level_as_text())
data["levels"] = list(
list("id" = SEC_LEVEL_GREEN, "name" = "Green", "icon" = "dove"),
list("id" = SEC_LEVEL_BLUE, "name" = "Blue", "icon" = "eye"),
@@ -464,7 +464,7 @@
to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.")
return
- if(seclevel2num(get_security_level()) >= SEC_LEVEL_RED) // There is a serious threat we gotta move no time to give them five minutes.
+ if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED) // There is a serious threat we gotta move no time to give them five minutes.
SSshuttle.emergency.canRecall = FALSE
SSshuttle.emergency.request(null, 0.5, null, " Automatic Crew Transfer", 1)
else
diff --git a/code/game/machinery/defib_mount.dm b/code/game/machinery/defib_mount.dm
index 0fe8508c0d6..0f0a9bee76b 100644
--- a/code/game/machinery/defib_mount.dm
+++ b/code/game/machinery/defib_mount.dm
@@ -46,7 +46,7 @@
. = ..()
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."
@@ -101,7 +101,7 @@
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/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm
index 4735a737b86..ba811e821eb 100644
--- a/code/game/machinery/doors/airlock_types.dm
+++ b/code/game/machinery/doors/airlock_types.dm
@@ -419,6 +419,19 @@
hackProof = TRUE
aiControlDisabled = AICONTROLDISABLED_ON
+/obj/machinery/door/airlock/highsecurity/red/Initialize(mapload)
+ . = ..()
+ if(is_station_level(z))
+ RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(on_security_level_update))
+
+/obj/machinery/door/airlock/highsecurity/red/proc/on_security_level_update(datum/source, previous_level_number, new_level_number)
+ SIGNAL_HANDLER
+
+ if(new_level_number >= SEC_LEVEL_RED)
+ unlock(TRUE)
+ else
+ lock(TRUE)
+
/obj/machinery/door/airlock/highsecurity/red/attackby(obj/C, mob/user, params)
if(!issilicon(user))
if(isElectrified())
diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm
index 31107bb5d1d..b6c8e51e00e 100644
--- a/code/game/machinery/firealarm.dm
+++ b/code/game/machinery/firealarm.dm
@@ -37,6 +37,24 @@ FIRE ALARM
var/last_time_pulled //used to prevent pulling spam by same persons
+/obj/machinery/firealarm/Initialize(mapload, location, direction, building)
+ . = ..()
+
+ if(building)
+ buildstage = 0
+ wiresexposed = TRUE
+ setDir(direction)
+ set_pixel_offsets_from_dir(26, -26, 26, -26)
+
+ LAZYADD(get_area(src).firealarms, src)
+
+ if(is_station_contact(z))
+ RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(on_security_level_update))
+
+ name = "fire alarm"
+ set_light(1, LIGHTING_MINIMUM_POWER) //for emissives
+ update_icon()
+
/obj/machinery/firealarm/no_alarm
report_fire_alarms = FALSE
@@ -73,7 +91,7 @@ FIRE ALARM
return
if(is_station_contact(z) && show_alert_level)
- . += "overlay_[get_security_level()]"
+ . += "overlay_[SSsecurity_level.get_current_level_as_text()]"
underlays += emissive_appearance(icon, "firealarm_overlay_lightmask")
if(!wiresexposed)
@@ -226,7 +244,7 @@ FIRE ALARM
if(stat & NOPOWER)
set_light(0)
return
- else if(GLOB.security_level == SEC_LEVEL_EPSILON)
+ else if(SSsecurity_level.get_current_level_as_number() == SEC_LEVEL_EPSILON)
set_light(2, 1, COLOR_WHITE)
return
else if(fire == !!light_power || fire == !!(light_power - 0.1))
@@ -244,6 +262,12 @@ FIRE ALARM
else if(A.fire)
GLOB.firealarm_soundloop.start(src)
+/obj/machinery/firealarm/proc/on_security_level_update(datum/source, previous_level_number, new_level_number)
+ SIGNAL_HANDLER
+
+ update_icon()
+ update_fire_light()
+
/obj/machinery/firealarm/power_change()
if(!..())
return
@@ -287,7 +311,7 @@ FIRE ALARM
. += "The fire alarm's wires are exposed by the unscrewed panel."
. += "The detection circuitry can be turned [detecting ? "off" : "on"] by pulsing the board."
- . += "It shows the alert level as: [capitalize(get_security_level())]."
+ . += "It shows the alert level as: [capitalize(SSsecurity_level.get_current_level_as_text())]."
/obj/machinery/firealarm/proc/reset()
if(!working || !report_fire_alarms)
@@ -303,23 +327,6 @@ FIRE ALARM
return
A.firealert(src) // Manually trigger alarms if the alarm isn't reported
-/obj/machinery/firealarm/New(location, direction, building)
- . = ..()
-
- if(building)
- buildstage = 0
- wiresexposed = TRUE
- setDir(direction)
- set_pixel_offsets_from_dir(26, -26, 26, -26)
-
- LAZYADD(get_area(src).firealarms, src)
-
-/obj/machinery/firealarm/Initialize(mapload)
- . = ..()
- name = "fire alarm"
- set_light(1, LIGHTING_MINIMUM_POWER) //for emissives
- update_icon()
-
/obj/machinery/firealarm/Destroy()
LAZYREMOVE(GLOB.firealarm_soundloop.output_atoms, src)
LAZYREMOVE(get_area(src).firealarms, src)
diff --git a/code/game/sound.dm b/code/game/sound.dm
index c7478164b41..edc0badf754 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -161,6 +161,13 @@ falloff_distance - Distance at which falloff begins. Sound is at peak volume (in
SEND_SOUND(src, S)
+/proc/sound_to_playing_players_on_station_level(soundin, volume = 100, vary = FALSE, frequency = 0, channel = 0, pressure_affected = FALSE, sound/S)
+ if(!S)
+ S = sound(get_sfx(soundin))
+ for(var/mob/m as anything in GLOB.player_list)
+ if(!isnewplayer(m) && is_station_level(m.z))
+ m.playsound_local(m, null, volume, vary, frequency, null, channel, pressure_affected, S)
+
/proc/sound_to_playing_players(soundin, volume = 100, vary = FALSE, frequency = 0, channel = 0, pressure_affected = FALSE, sound/S)
if(!S)
S = sound(get_sfx(soundin))
diff --git a/code/game/world.dm b/code/game/world.dm
index 1bd4c6ec672..2fbd08764fa 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -221,7 +221,7 @@ GLOBAL_LIST_EMPTY(world_topic_handlers)
s += "
[GLOB.configuration.general.server_tag_line]"
if(SSticker && ROUND_TIME > 0)
- s += "
[round(ROUND_TIME / 36000)]:[add_zero(num2text(ROUND_TIME / 600 % 60), 2)], [capitalize(get_security_level())]"
+ s += "
[round(ROUND_TIME / 36000)]:[add_zero(num2text(ROUND_TIME / 600 % 60), 2)], [capitalize(SSsecurity_level.get_current_level_as_text())]"
else
s += "
STARTING"
diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm
index 95e36f33eca..a348cc5a388 100644
--- a/code/modules/admin/secrets.dm
+++ b/code/modules/admin/secrets.dm
@@ -63,6 +63,11 @@
if(1)
if(check_rights((R_EVENT|R_SERVER),0))
+ var/security_levels_data = ""
+ for (var/level_name in SSsecurity_level.available_levels)
+ var/datum/security_level/this_level = SSsecurity_level.available_levels[level_name]
+ security_levels_data += "[this_level.name]"
+
dat += {"
IC Events
@@ -72,12 +77,7 @@
Send in the Deathsquad
Send in a Gimmick Team
Change Security Level
- Security Level - Green
- Security Level - Blue
- Security Level - Red
- Security Level - Gamma
- Security Level - Epsilon
- Security Level - Delta
+ [security_levels_data]
Create Weather
Weather - Ash Storm
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index c141ad3aa92..ac0855591e1 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -3123,24 +3123,10 @@
if(confirmation == "No")
return
makeThunderdomeTeams()
- if("securitylevel0")
- set_security_level(0)
- message_admins("[key_name_admin(usr)] change security level to Green.", 1)
- if("securitylevel1")
- set_security_level(1)
- message_admins("[key_name_admin(usr)] change security level to Blue.", 1)
- if("securitylevel2")
- set_security_level(2)
- message_admins("[key_name_admin(usr)] change security level to Red.", 1)
- if("securitylevel3")
- set_security_level(3)
- message_admins("[key_name_admin(usr)] change security level to Gamma.", 1)
- if("securitylevel4")
- set_security_level(4)
- message_admins("[key_name_admin(usr)] change security level to Epsilon.", 1)
- if("securitylevel5")
- set_security_level(5)
- message_admins("[key_name_admin(usr)] change security level to Delta.", 1)
+ if("securitylevel")
+ var/level_number = text2num(href_list["number"])
+ SSsecurity_level.set_level(level_number)
+ message_admins("[key_name_admin(usr)] change security level to [SSsecurity_level.number_level_to_text(level_number)].")
if("moveminingshuttle")
SSblackbox.record_feedback("tally", "admin_secrets_fun_used", 1, "Send Mining Shuttle")
if(!SSshuttle.toggleShuttle("mining","mining_home","mining_away"))
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 1a9a3e946b2..3ef4f2def44 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -848,7 +848,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
else
SSshuttle.emergency.canRecall = FALSE
- if(seclevel2num(get_security_level()) >= SEC_LEVEL_RED)
+ if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED)
SSshuttle.emergency.request(coefficient = 0.5, redAlert = TRUE)
else
SSshuttle.emergency.request()
diff --git a/code/modules/events/traders.dm b/code/modules/events/traders.dm
index 2ae8b378a3d..384978c872f 100644
--- a/code/modules/events/traders.dm
+++ b/code/modules/events/traders.dm
@@ -15,7 +15,7 @@ GLOBAL_LIST_INIT(unused_trade_stations, list("sol"))
/datum/event/traders/fake_announce()
. = TRUE
- if(seclevel2num(get_security_level()) >= SEC_LEVEL_RED)
+ if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED)
GLOB.minor_announcement.Announce("A trading shuttle from Jupiter Station has been denied docking permission due to the heightened security alert aboard [station_name()].", "Trader Shuttle Docking Request Refused")
return
GLOB.minor_announcement.Announce("A trading shuttle from Jupiter Station has been granted docking permission at [station_name()] arrivals port 4.", "Trader Shuttle Docking Request Accepted")
@@ -24,7 +24,7 @@ GLOBAL_LIST_INIT(unused_trade_stations, list("sol"))
/datum/event/traders/start()
if(!station) // If there are no unused stations, just no.
return
- if(seclevel2num(get_security_level()) >= SEC_LEVEL_RED)
+ if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED)
GLOB.minor_announcement.Announce("A trading shuttle from Jupiter Station has been denied docking permission due to the heightened security alert aboard [station_name()].", "Trader Shuttle Docking Request Refused")
// if the docking request was refused, fire another major event in 60 seconds
var/datum/event_container/EC = SSevents.event_containers[EVENT_LEVEL_MAJOR]
diff --git a/code/modules/mob/living/silicon/ai/ai_death.dm b/code/modules/mob/living/silicon/ai/ai_death.dm
index 60856ab0ebe..6f170c292f1 100644
--- a/code/modules/mob/living/silicon/ai/ai_death.dm
+++ b/code/modules/mob/living/silicon/ai/ai_death.dm
@@ -16,7 +16,7 @@
SSshuttle.autoEvac()
if(nuking)
- set_security_level("red")
+ SSsecurity_level.set_level(SEC_LEVEL_RED)
nuking = FALSE
for(var/obj/item/pinpointer/point in GLOB.pinpointer_list)
point.the_disk = null //Point back to the disk.
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 0a210162c93..825f2751327 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -446,7 +446,7 @@
var/dat = ""
dat += "Round Duration: [round(hours)]h [round(mins)]m
"
- dat += "The station alert level is: [get_security_level_colors()]
"
+ dat += "The station alert level is: [SSsecurity_level.get_colored_current_security_level_name()]
"
if(SSshuttle.emergency.mode >= SHUTTLE_ESCAPE)
dat += "The station has been evacuated.
"
diff --git a/code/modules/power/apc/apc_malfunction.dm b/code/modules/power/apc/apc_malfunction.dm
index ced656f13f6..1494cef300e 100644
--- a/code/modules/power/apc/apc_malfunction.dm
+++ b/code/modules/power/apc/apc_malfunction.dm
@@ -49,7 +49,7 @@
var/datum/action/innate/ai/return_to_core/R = new
R.Grant(occupier)
occupier.cancel_camera()
- if((seclevel2num(get_security_level()) == SEC_LEVEL_DELTA) && malf.nuking)
+ if((SSsecurity_level.get_current_level_as_number() == SEC_LEVEL_DELTA) && malf.nuking)
for(var/obj/item/pinpointer/point in GLOB.pinpointer_list)
point.the_disk = src //the pinpointer will detect the shunted AI
@@ -62,7 +62,7 @@
occupier.parent.adjustOxyLoss(occupier.getOxyLoss())
occupier.parent.cancel_camera()
qdel(occupier)
- if(seclevel2num(get_security_level()) == SEC_LEVEL_DELTA)
+ if(SSsecurity_level.get_current_level_as_number() == SEC_LEVEL_DELTA)
for(var/obj/item/pinpointer/point in GLOB.pinpointer_list)
for(var/mob/living/silicon/ai/A in GLOB.ai_list)
if((A.stat != DEAD) && A.nuking)
diff --git a/code/modules/power/lights.dm b/code/modules/power/lights.dm
index 03091088a0c..99168174b2f 100644
--- a/code/modules/power/lights.dm
+++ b/code/modules/power/lights.dm
@@ -256,6 +256,11 @@
// create a new lighting fixture
/obj/machinery/light/Initialize(mapload)
. = ..()
+
+ if(is_station_level(z))
+ RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGE_PLANNED, PROC_REF(on_security_level_change_planned))
+ RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(on_security_level_update))
+
var/area/A = get_area(src)
if(A && !A.requires_power)
on = TRUE
@@ -272,11 +277,39 @@
break_light_tube(TRUE)
update(FALSE, TRUE, FALSE)
+/obj/machinery/light/proc/on_security_level_change_planned(datum/source, previous_level_number, new_level_number)
+ SIGNAL_HANDLER
+
+ if(status != LIGHT_OK)
+ return
+
+ if(new_level_number == SEC_LEVEL_EPSILON)
+ fire_mode = FALSE
+ emergency_mode = TRUE
+ on = FALSE
+ INVOKE_ASYNC(src, PROC_REF(update), FALSE)
+
+/obj/machinery/light/proc/on_security_level_update(datum/source, previous_level_number, new_level_number)
+ SIGNAL_HANDLER
+
+ if(status != LIGHT_OK)
+ return
+
+ if(new_level_number >= SEC_LEVEL_EPSILON)
+ fire_mode = TRUE
+ emergency_mode = TRUE
+ on = FALSE
+ else
+ fire_mode = FALSE
+ emergency_mode = FALSE
+ on = TRUE
+
+ INVOKE_ASYNC(src, PROC_REF(update), FALSE)
+
/obj/machinery/light/Destroy()
var/area/A = get_area(src)
if(A)
on = FALSE
-// A.update_lights()
return ..()
/obj/machinery/light/update_icon_state()
diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm
index 0beaad86d60..f29494fdac5 100644
--- a/code/modules/security_levels/keycard_authentication.dm
+++ b/code/modules/security_levels/keycard_authentication.dm
@@ -95,7 +95,7 @@
/obj/machinery/keycard_auth/ui_data()
var/list/data = list()
- data["redAvailable"] = GLOB.security_level == SEC_LEVEL_RED ? FALSE : TRUE
+ data["redAvailable"] = SSsecurity_level.get_current_level_as_number() != SEC_LEVEL_RED
data["swiping"] = swiping
data["busy"] = busy
data["event"] = active && event_source && event_source.event ? event_source.event : event
@@ -172,7 +172,7 @@
SHOULD_NOT_SLEEP(TRUE) // trigger_armed_response_team sleeps, which can cause issues for procs that call trigger_event(). We want to avoid that
switch(event)
if("Red Alert")
- INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(set_security_level), SEC_LEVEL_RED)
+ INVOKE_ASYNC(SSsecurity_level, TYPE_PROC_REF(/datum/controller/subsystem/security_level, set_level), SEC_LEVEL_RED)
if("Grant Emergency Maintenance Access")
make_maint_all_access()
if("Revoke Emergency Maintenance Access")
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 00000000000..12273e95f26
--- /dev/null
+++ b/code/modules/security_levels/security_level_datums.dm
@@ -0,0 +1,145 @@
+/**
+ * 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 delay, after which the security level will be set
+ var/set_delay = 0
+ /// The sound that we will play when elevated to this security level
+ var/elevating_to_sound
+ /// The sound that we will play when lowered to this security level
+ var/lowering_to_sound
+ /// The AI announcement sound about code change, that will be played after main sound
+ var/ai_announcement_sound
+ /// Color of security level
+ var/color
+ /// The status display that will be posted to all status displays on security level set
+ var/status_display_mode = STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME
+ /// The status display data that will be posted to all status displays on security level set
+ var/status_display_data = ""
+ /// Our announcement title when lowering to this level
+ var/lowering_to_announcement_title = "Not set."
+ /// Our announcement when lowering to this level
+ var/lowering_to_announcement_text = "Not set."
+ /// Our announcement title when elevating to this level
+ var/elevating_to_announcement_title = "Not set."
+ /// Our announcement when elevating to this level
+ var/elevating_to_announcement_text = "Not set."
+
+/**
+ * Should contain actions that must be completed before actual security level set
+ */
+/datum/security_level/proc/pre_change()
+ return
+
+/**
+ * GREEN
+ *
+ * No threats
+ */
+/datum/security_level/green
+ name = "green"
+ number_level = SEC_LEVEL_GREEN
+ ai_announcement_sound = 'sound/AI/green.ogg'
+ color = "limegreen"
+ lowering_to_announcement_title = "Attention! Security level lowered to Green."
+ lowering_to_announcement_text = "All threats to the station have passed. All weapons need to be holstered and privacy laws are once again fully enforced."
+
+/**
+ * BLUE
+ *
+ * Caution advised
+ */
+/datum/security_level/blue
+ name = "blue"
+ number_level = SEC_LEVEL_BLUE
+ elevating_to_sound = 'sound/misc/notice1.ogg'
+ ai_announcement_sound = 'sound/AI/blue.ogg'
+ color = "dodgerblue"
+ lowering_to_announcement_title = "Attention! Security level lowered to Blue."
+ lowering_to_announcement_text = "The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed."
+ elevating_to_announcement_title = "Attention! Security level elevated to Blue."
+ elevating_to_announcement_text = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible and random searches are permitted."
+
+/**
+ * RED
+ *
+ * Hostile threats
+ */
+/datum/security_level/red
+ name = "red"
+ number_level = SEC_LEVEL_RED
+ elevating_to_sound = 'sound/misc/notice1.ogg'
+ ai_announcement_sound = 'sound/AI/red.ogg'
+ color = "red"
+ status_display_mode = STATUS_DISPLAY_ALERT
+ status_display_data = "redalert"
+ lowering_to_announcement_title = "Attention! Code Red!"
+ lowering_to_announcement_text = "The station's self-destruct mechanism has been deactivated, but there is still an immediate and serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised."
+ elevating_to_announcement_title = "Attention! Code Red!"
+ elevating_to_announcement_text = "There is an immediate and serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised."
+
+/**
+ * Gamma
+ *
+ * Station major hostile threats
+ */
+/datum/security_level/gamma
+ name = "gamma"
+ number_level = SEC_LEVEL_GAMMA
+ lowering_to_sound = 'sound/effects/new_siren.ogg'
+ elevating_to_sound = 'sound/effects/new_siren.ogg'
+ ai_announcement_sound = 'sound/AI/gamma.ogg'
+ color = "gold"
+ status_display_mode = STATUS_DISPLAY_ALERT
+ status_display_data = "gammaalert"
+ lowering_to_announcement_title = "Attention! Gamma security level activated!"
+ lowering_to_announcement_text = "Central Command has ordered the Gamma security level on the station. Security is to have weapons equipped at all times, and all civilians are to immediately seek their nearest head for transportation to a secure location."
+ elevating_to_announcement_text = "Central Command has ordered the Gamma security level on the station. Security is to have weapons equipped at all times, and all civilians are to immediately seek their nearest head for transportation to a secure location."
+ elevating_to_announcement_title = "Attention! Gamma security level activated!"
+
+/**
+ * Epsilon
+ *
+ * Station is not longer under the Central Command and to be destroyed by Death Squad (Or maybe not)
+ */
+/datum/security_level/epsilon
+ name = "epsilon"
+ number_level = SEC_LEVEL_EPSILON
+ set_delay = 15 SECONDS
+ lowering_to_sound = 'sound/effects/purge_siren.ogg'
+ elevating_to_sound = 'sound/effects/purge_siren.ogg'
+ ai_announcement_sound = 'sound/AI/epsilon.ogg'
+ color = "blueviolet"
+ status_display_mode = STATUS_DISPLAY_ALERT
+ status_display_data = "epsilonalert"
+ lowering_to_announcement_title = "Attention! Epsilon security level activated!"
+ lowering_to_announcement_text = "Central Command has ordered the Epsilon security level on the station. Consider all contracts terminated."
+ elevating_to_announcement_title = "Attention! Epsilon security level activated!"
+ elevating_to_announcement_text = "Central Command has ordered the Epsilon security level on the station. Consider all contracts terminated."
+
+/datum/security_level/epsilon/pre_change()
+ sound_to_playing_players_on_station_level(S = sound('sound/effects/powerloss.ogg'))
+
+/**
+ * DELTA
+ *
+ * Station self-destruiction mechanism has been engaged
+ */
+/datum/security_level/delta
+ name = "delta"
+ number_level = SEC_LEVEL_DELTA
+ elevating_to_sound = 'sound/effects/delta_klaxon.ogg'
+ ai_announcement_sound = 'sound/AI/delta.ogg'
+ color = "orangered"
+ status_display_mode = STATUS_DISPLAY_ALERT
+ status_display_data = "deltaalert"
+ elevating_to_announcement_title = "Attention! Delta security level reached!"
+ elevating_to_announcement_text = "The station's self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill."
diff --git a/code/modules/security_levels/security_levels.dm b/code/modules/security_levels/security_levels.dm
deleted file mode 100644
index c84ed819bcb..00000000000
--- a/code/modules/security_levels/security_levels.dm
+++ /dev/null
@@ -1,225 +0,0 @@
-GLOBAL_VAR_INIT(security_level, 0)
-//0 = code green
-//1 = code blue
-//2 = code red
-//3 = gamma
-//4 = epsilon
-//5 = code delta
-
-//config.alert_desc_blue_downto
-GLOBAL_DATUM_INIT(security_announcement, /datum/announcer, new(config_type = /datum/announcement_configuration/security))
-
-/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("gamma")
- level = SEC_LEVEL_GAMMA
- if("epsilon")
- level = SEC_LEVEL_EPSILON
- 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)
- if(level >= SEC_LEVEL_RED && GLOB.security_level < SEC_LEVEL_RED)
- // Mark down this time to prevent shuttle cheese
- SSshuttle.emergency_sec_level_time = world.time
-
- switch(level)
- if(SEC_LEVEL_GREEN)
- GLOB.security_announcement.Announce("All threats to the station have passed. All weapons need to be holstered and privacy laws are once again fully enforced.","Attention! Security level lowered to green.", new_sound2 = 'sound/AI/green.ogg')
- GLOB.security_level = SEC_LEVEL_GREEN
- unset_stationwide_emergency_lighting()
- post_status(STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME)
- update_firealarms()
-
- if(SEC_LEVEL_BLUE)
- if(GLOB.security_level < SEC_LEVEL_BLUE)
- GLOB.security_announcement.Announce("The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible and random searches are permitted.", "Attention! Security level elevated to blue.",
- new_sound = 'sound/misc/notice1.ogg',
- new_sound2 = 'sound/AI/blue.ogg')
- else
- GLOB.security_announcement.Announce("The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed.", "Attention! Security level lowered to blue.", new_sound2 = 'sound/AI/blue.ogg')
- GLOB.security_level = SEC_LEVEL_BLUE
-
- post_status(STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME)
- unset_stationwide_emergency_lighting()
- update_firealarms()
-
- if(SEC_LEVEL_RED)
- if(GLOB.security_level < SEC_LEVEL_RED)
- GLOB.security_announcement.Announce("There is an immediate and serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised.", "Attention! Code Red!",
- new_sound = 'sound/misc/notice1.ogg',
- new_sound2 = 'sound/AI/red.ogg')
- else
- GLOB.security_announcement.Announce("The station's self-destruct mechanism has been deactivated, but there is still an immediate and serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised.", "Attention! Code Red!", new_sound2 = 'sound/AI/red.ogg')
- unset_stationwide_emergency_lighting()
- GLOB.security_level = SEC_LEVEL_RED
-
- var/obj/machinery/door/airlock/highsecurity/red/R = locate(/obj/machinery/door/airlock/highsecurity/red) in GLOB.airlocks
- if(R && is_station_level(R.z))
- R.unlock(TRUE)
-
- post_status(STATUS_DISPLAY_ALERT, "redalert")
- update_firealarms()
-
- if(SEC_LEVEL_GAMMA)
- GLOB.security_announcement.Announce("Central Command has ordered the Gamma security level on the station. Security is to have weapons equipped at all times, and all civilians are to immediately seek their nearest head for transportation to a secure location.", "Attention! Gamma security level activated!", 'sound/effects/new_siren.ogg', new_sound2 = 'sound/AI/gamma.ogg')
- GLOB.security_level = SEC_LEVEL_GAMMA
-
- if(GLOB.security_level < SEC_LEVEL_RED)
- for(var/obj/machinery/door/airlock/highsecurity/red/R in GLOB.airlocks)
- if(is_station_level(R.z))
- R.unlock(TRUE)
-
- post_status(STATUS_DISPLAY_ALERT, "gammaalert")
- update_firealarms()
-
- if(SEC_LEVEL_EPSILON)
- for(var/mob/M in GLOB.player_list)
- var/turf/T = get_turf(M)
- if(!M.client || !is_station_level(T.z))
- continue
- SEND_SOUND(M, sound('sound/effects/powerloss.ogg'))
- set_stationwide_emergency_lighting()
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(epsilon_process)), 15 SECONDS)
- SSblackbox.record_feedback("tally", "security_level_changes", 1, level)
- return
-
- if(SEC_LEVEL_DELTA)
- var/temp_sound = GLOB.security_announcement.config.sound
- GLOB.security_announcement.config.sound = null
- GLOB.security_announcement.Announce("The station's self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill.","Attention! Delta security level reached!",
- new_sound = 'sound/effects/delta_klaxon.ogg',
- new_sound2 = 'sound/AI/delta.ogg')
- GLOB.security_announcement.config.sound = temp_sound
- GLOB.security_level = SEC_LEVEL_DELTA
- post_status(STATUS_DISPLAY_ALERT, "deltaalert")
- update_firealarms()
- set_stationwide_emergency_lighting()
- SSblackbox.record_feedback("tally", "security_level_changes", 1, level)
- return
-
- SSnightshift.check_nightshift(TRUE)
- SSblackbox.record_feedback("tally", "security_level_changes", 1, level)
-
- else
- return
-
-/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_GAMMA)
- return "gamma"
- if(SEC_LEVEL_EPSILON)
- return "epsilon"
- if(SEC_LEVEL_DELTA)
- return "delta"
-
-/proc/update_firealarms()
- for(var/obj/machinery/firealarm/FA in GLOB.machines)
- if(is_station_contact(FA.z))
- FA.update_icon()
- FA.update_fire_light()
-
-/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_GAMMA)
- return "gamma"
- if(SEC_LEVEL_EPSILON)
- return "epsilon"
- 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("gamma")
- return SEC_LEVEL_GAMMA
- if("epsilon")
- return SEC_LEVEL_EPSILON
- if("delta")
- return SEC_LEVEL_DELTA
-
-/proc/get_security_level_colors()
- 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_GAMMA)
- return "Gamma"
- if(SEC_LEVEL_EPSILON)
- return "Epsilon"
- if(SEC_LEVEL_DELTA)
- return "Delta"
-
-/proc/set_stationwide_emergency_lighting()
- for(var/obj/machinery/power/apc/A in GLOB.apcs)
- var/area/AR = get_area(A)
- if(!is_station_level(A.z))
- continue
- A.emergency_lights = FALSE
- AR.area_emergency_mode = TRUE
- for(var/obj/machinery/light/L in A.apc_area)
- if(L.status)
- continue
- if(GLOB.security_level == SEC_LEVEL_DELTA)
- L.fire_mode = TRUE
- L.on = FALSE
- L.emergency_mode = TRUE
- INVOKE_ASYNC(L, TYPE_PROC_REF(/obj/machinery/light, update), FALSE)
-
-/proc/unset_stationwide_emergency_lighting()
- for(var/area/A as anything in GLOB.all_areas)
- if(!is_station_level(A.z))
- continue
- if(!A.area_emergency_mode)
- continue
- A.area_emergency_mode = FALSE
- for(var/obj/machinery/light/L in A)
- if(A.fire)
- continue
- if(L.status)
- continue
- L.fire_mode = FALSE
- L.emergency_mode = FALSE
- L.on = TRUE
- INVOKE_ASYNC(L, TYPE_PROC_REF(/obj/machinery/light, update), FALSE)
-
-/proc/epsilon_process()
- GLOB.security_announcement.Announce("Central Command has ordered the Epsilon security level on the station. Consider all contracts terminated.", "Attention! Epsilon security level activated!", 'sound/effects/purge_siren.ogg')
- GLOB.security_level = SEC_LEVEL_EPSILON
- post_status(STATUS_DISPLAY_ALERT, "epsilonalert")
- for(var/area/A as anything in GLOB.all_areas)
- if(!is_station_level(A.z))
- continue
- for(var/obj/machinery/light/L in A)
- if(L.status)
- continue
- L.fire_mode = TRUE
- L.update()
- update_firealarms()
diff --git a/code/modules/tgui/modules/ert_manager.dm b/code/modules/tgui/modules/ert_manager.dm
index da04210d95c..2bee0c86eb8 100644
--- a/code/modules/tgui/modules/ert_manager.dm
+++ b/code/modules/tgui/modules/ert_manager.dm
@@ -20,18 +20,9 @@
/datum/ui_module/ert_manager/ui_data(mob/user)
var/list/data = list()
- data["str_security_level"] = capitalize(get_security_level())
- switch(GLOB.security_level)
- if(SEC_LEVEL_GREEN)
- data["security_level_color"] = "green"
- if(SEC_LEVEL_BLUE)
- data["security_level_color"] = "blue"
- if(SEC_LEVEL_RED)
- data["security_level_color"] = "red"
- else
- data["security_level_color"] = "purple"
+ data["str_security_level"] = capitalize(SSsecurity_level.get_current_level_as_text())
+ data["security_level_color"] = SSsecurity_level.current_security_level.color
data["ert_request_answered"] = GLOB.ert_request_answered
-
data["ert_type"] = ert_type
data["com"] = commander_slots
data["sec"] = security_slots
diff --git a/code/modules/unit_tests/announcements.dm b/code/modules/unit_tests/announcements.dm
index 898645dc337..2db837dab31 100644
--- a/code/modules/unit_tests/announcements.dm
+++ b/code/modules/unit_tests/announcements.dm
@@ -37,12 +37,12 @@
ai_announcer.author = "AI-NAME-0345"
ai_announcer.Announce("AI only get one input box so here ya go")
- set_security_level(SEC_LEVEL_RED)
- set_security_level(SEC_LEVEL_GAMMA)
- set_security_level(SEC_LEVEL_EPSILON)
- set_security_level(SEC_LEVEL_RED)
- set_security_level(SEC_LEVEL_BLUE)
- set_security_level(SEC_LEVEL_GREEN)
+ SSsecurity_level.set_level(SEC_LEVEL_RED)
+ SSsecurity_level.set_level(SEC_LEVEL_GAMMA)
+ SSsecurity_level.set_level(SEC_LEVEL_EPSILON)
+ SSsecurity_level.set_level(SEC_LEVEL_RED)
+ SSsecurity_level.set_level(SEC_LEVEL_BLUE)
+ SSsecurity_level.set_level(SEC_LEVEL_GREEN)
var/reason = "We're getting the fuck out of here"
var/redAlert = TRUE
diff --git a/code/modules/world_topic/status.dm b/code/modules/world_topic/status.dm
index 960cad2f9a1..c4c4d739b5a 100644
--- a/code/modules/world_topic/status.dm
+++ b/code/modules/world_topic/status.dm
@@ -47,7 +47,7 @@
if(key_valid)
if(SSticker.mode)
status_info["real_mode"] = SSticker.mode.name
- status_info["security_level"] = get_security_level()
+ status_info["security_level"] = SSsecurity_level.get_current_level_as_text()
status_info["ticker_state"] = SSticker.current_state
if(SSshuttle.emergency)
diff --git a/paradise.dme b/paradise.dme
index b3b6b4487e2..ea052dabf96 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -280,6 +280,7 @@
#include "code\controllers\subsystem\SSradiation.dm"
#include "code\controllers\subsystem\SSredis.dm"
#include "code\controllers\subsystem\SSrunechat.dm"
+#include "code\controllers\subsystem\SSsecurity_level.dm"
#include "code\controllers\subsystem\SSshuttles.dm"
#include "code\controllers\subsystem\SSspacedrift.dm"
#include "code\controllers\subsystem\SSsun.dm"
@@ -2598,7 +2599,7 @@
#include "code\modules\ruins\objects_and_mobs\necropolis_gate.dm"
#include "code\modules\ruins\spaceruin_code\voyager.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\server_commands\servermsg.dm"
#include "code\modules\server_commands\commands\newroundannounce.dm"
#include "code\modules\shuttle\assault_pod.dm"