diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm
index 4368757352..644eaf1d65 100644
--- a/code/_globalvars/lists/mobs.dm
+++ b/code/_globalvars/lists/mobs.dm
@@ -13,6 +13,7 @@ GLOBAL_LIST_EMPTY(player_list) //all mobs **with clients attached**. Excludes
GLOBAL_LIST_EMPTY(mob_list) //all mobs, including clientless
GLOBAL_LIST_EMPTY(mob_directory) //mob_id -> mob
GLOBAL_LIST_EMPTY(living_mob_list) //all alive mobs, including clientless. Excludes /mob/dead/new_player
+GLOBAL_LIST_EMPTY(drones_list)
GLOBAL_LIST_EMPTY(dead_mob_list) //all dead mobs, including clientless. Excludes /mob/dead/new_player
GLOBAL_LIST_EMPTY(joined_player_list) //all clients that have joined the game at round-start or as a latejoin.
GLOBAL_LIST_EMPTY(silicon_mobs) //all silicon mobs
diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm
index 5defb16551..12173b21b7 100644
--- a/code/_globalvars/lists/objects.dm
+++ b/code/_globalvars/lists/objects.dm
@@ -36,4 +36,5 @@ GLOBAL_LIST_EMPTY(wire_name_directory)
GLOBAL_LIST_EMPTY(ai_status_displays)
-GLOBAL_LIST_EMPTY(mob_spawners) // All mob_spawn objects
\ No newline at end of file
+GLOBAL_LIST_EMPTY(mob_spawners) // All mob_spawn objects
+GLOBAL_LIST_EMPTY(alert_consoles) // Station alert consoles, /obj/machinery/computer/station_alert
\ No newline at end of file
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 75a6581aa9..ff33f8e32a 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -58,6 +58,8 @@
flags_1 = CAN_BE_DIRTY_1
var/list/firedoors
+ var/list/cameras
+ var/list/firealarms
var/firedoors_last_closed_on = 0
/*Adding a wizard area teleport list because motherfucking lag -- Urist*/
@@ -102,7 +104,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
uid = ++global_uid
related = list(src)
map_name = name // Save the initial (the name set in the map) name of the area.
-
+
if(requires_power)
luminosity = 0
else
@@ -154,27 +156,28 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if (state != poweralm)
poweralm = state
if(istype(source)) //Only report power alarms on the z-level where the source is located.
- var/list/cameras = list()
- for (var/obj/machinery/camera/C in src)
- cameras += C
- for (var/mob/living/silicon/aiPlayer in GLOB.player_list)
+ for (var/item in GLOB.silicon_mobs)
+ var/mob/living/silicon/aiPlayer = item
if (state == 1)
aiPlayer.cancelAlarm("Power", src, source)
else
aiPlayer.triggerAlarm("Power", src, cameras, source)
- for(var/obj/machinery/computer/station_alert/a in GLOB.machines)
+ for (var/item in GLOB.alert_consoles)
+ var/obj/machinery/computer/station_alert/a = item
if(state == 1)
a.cancelAlarm("Power", src, source)
else
a.triggerAlarm("Power", src, cameras, source)
- for(var/mob/living/simple_animal/drone/D in GLOB.mob_list)
+ for (var/item in GLOB.drones_list)
+ var/mob/living/simple_animal/drone/D = item
if(state == 1)
D.cancelAlarm("Power", src, source)
else
D.triggerAlarm("Power", src, cameras, source)
- for(var/datum/computer_file/program/alarm_monitor/p in GLOB.alarmdisplay)
+ for(var/item in GLOB.alarmdisplay)
+ var/datum/computer_file/program/alarm_monitor/p = item
if(state == 1)
p.cancelAlarm("Power", src, source)
else
@@ -185,26 +188,35 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if (danger_level==2)
var/list/cameras = list()
for(var/area/RA in related)
- for(var/obj/machinery/camera/C in RA)
+ for (var/item in RA.cameras)
+ var/obj/machinery/camera/C = item
cameras += C
- for(var/mob/living/silicon/aiPlayer in GLOB.player_list)
+ for (var/item in GLOB.silicon_mobs)
+ var/mob/living/silicon/aiPlayer = item
aiPlayer.triggerAlarm("Atmosphere", src, cameras, source)
- for(var/obj/machinery/computer/station_alert/a in GLOB.machines)
+ for (var/item in GLOB.alert_consoles)
+ var/obj/machinery/computer/station_alert/a = item
a.triggerAlarm("Atmosphere", src, cameras, source)
- for(var/mob/living/simple_animal/drone/D in GLOB.mob_list)
+ for (var/item in GLOB.drones_list)
+ var/mob/living/simple_animal/drone/D = item
D.triggerAlarm("Atmosphere", src, cameras, source)
- for(var/datum/computer_file/program/alarm_monitor/p in GLOB.alarmdisplay)
+ for(var/item in GLOB.alarmdisplay)
+ var/datum/computer_file/program/alarm_monitor/p = item
p.triggerAlarm("Atmosphere", src, cameras, source)
else if (src.atmosalm == 2)
- for(var/mob/living/silicon/aiPlayer in GLOB.player_list)
+ for (var/item in GLOB.silicon_mobs)
+ var/mob/living/silicon/aiPlayer = item
aiPlayer.cancelAlarm("Atmosphere", src, source)
- for(var/obj/machinery/computer/station_alert/a in GLOB.machines)
+ for (var/item in GLOB.alert_consoles)
+ var/obj/machinery/computer/station_alert/a = item
a.cancelAlarm("Atmosphere", src, source)
- for(var/mob/living/simple_animal/drone/D in GLOB.mob_list)
+ for (var/item in GLOB.drones_list)
+ var/mob/living/simple_animal/drone/D = item
D.cancelAlarm("Atmosphere", src, source)
- for(var/datum/computer_file/program/alarm_monitor/p in GLOB.alarmdisplay)
+ for(var/item in GLOB.alarmdisplay)
+ var/datum/computer_file/program/alarm_monitor/p = item
p.cancelAlarm("Atmosphere", src, source)
src.atmosalm = danger_level
@@ -239,18 +251,24 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if (!( RA.fire ))
RA.set_fire_alarm_effect()
RA.ModifyFiredoors(FALSE)
- for(var/obj/machinery/firealarm/F in RA)
+ for(var/item in RA.firealarms)
+ var/obj/machinery/firealarm/F = item
F.update_icon()
- for (var/obj/machinery/camera/C in RA)
+ for (var/item in RA.cameras)
+ var/obj/machinery/camera/C = item
cameras += C
- for (var/obj/machinery/computer/station_alert/a in GLOB.machines)
+ for (var/item in GLOB.alert_consoles)
+ var/obj/machinery/computer/station_alert/a = item
a.triggerAlarm("Fire", src, cameras, source)
- for (var/mob/living/silicon/aiPlayer in GLOB.player_list)
+ for (var/item in GLOB.silicon_mobs)
+ var/mob/living/silicon/aiPlayer = item
aiPlayer.triggerAlarm("Fire", src, cameras, source)
- for (var/mob/living/simple_animal/drone/D in GLOB.mob_list)
+ for (var/item in GLOB.drones_list)
+ var/mob/living/simple_animal/drone/D = item
D.triggerAlarm("Fire", src, cameras, source)
- for(var/datum/computer_file/program/alarm_monitor/p in GLOB.alarmdisplay)
+ for(var/item in GLOB.alarmdisplay)
+ var/datum/computer_file/program/alarm_monitor/p = item
p.triggerAlarm("Fire", src, cameras, source)
START_PROCESSING(SSobj, src)
@@ -262,16 +280,21 @@ GLOBAL_LIST_EMPTY(teleportlocs)
RA.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
RA.updateicon()
RA.ModifyFiredoors(TRUE)
- for(var/obj/machinery/firealarm/F in RA)
+ for(var/item in RA.firealarms)
+ var/obj/machinery/firealarm/F = item
F.update_icon()
- for (var/mob/living/silicon/aiPlayer in GLOB.player_list)
+ for (var/item in GLOB.silicon_mobs)
+ var/mob/living/silicon/aiPlayer = item
aiPlayer.cancelAlarm("Fire", src, source)
- for (var/obj/machinery/computer/station_alert/a in GLOB.machines)
+ for (var/item in GLOB.alert_consoles)
+ var/obj/machinery/computer/station_alert/a = item
a.cancelAlarm("Fire", src, source)
- for (var/mob/living/simple_animal/drone/D in GLOB.mob_list)
+ for (var/item in GLOB.drones_list)
+ var/mob/living/simple_animal/drone/D = item
D.cancelAlarm("Fire", src, source)
- for(var/datum/computer_file/program/alarm_monitor/p in GLOB.alarmdisplay)
+ for(var/item in GLOB.alarmdisplay)
+ var/datum/computer_file/program/alarm_monitor/p = item
p.cancelAlarm("Fire", src, source)
STOP_PROCESSING(SSobj, src)
@@ -299,7 +322,8 @@ GLOBAL_LIST_EMPTY(teleportlocs)
//Lockdown airlocks
for(var/obj/machinery/door/DOOR in RA)
close_and_lock_door(DOOR)
- for (var/obj/machinery/camera/C in RA)
+ for (var/item in RA.cameras)
+ var/obj/machinery/camera/C = item
cameras += C
for (var/mob/living/silicon/SILICON in GLOB.player_list)
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 17a65f7033..93b2904606 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -26,6 +26,7 @@
var/invuln = null
var/obj/item/device/camera_bug/bug = null
var/obj/structure/camera_assembly/assembly = null
+ var/area/myarea = null
//OTHER
@@ -47,6 +48,9 @@
assembly.state = 4
GLOB.cameranet.cameras += src
GLOB.cameranet.addCamera(src)
+ if (isturf(loc))
+ myarea = get_area(src)
+ LAZYADD(myarea.cameras, src)
proximity_monitor = new(src, 1)
if(mapload && (z in GLOB.station_z_levels) && prob(3) && !start_active)
@@ -54,6 +58,8 @@
/obj/machinery/camera/Destroy()
toggle_cam(null, 0) //kick anyone viewing out
+ if(isarea(myarea))
+ LAZYREMOVE(myarea.cameras, src)
if(assembly)
qdel(assembly)
assembly = null
@@ -64,7 +70,6 @@
bug = null
GLOB.cameranet.removeCamera(src) //Will handle removal from the camera network and the chunks, so we don't need to worry about that
GLOB.cameranet.cameras -= src
- GLOB.cameranet.removeCamera(src)
return ..()
/obj/machinery/camera/emp_act(severity)
@@ -119,6 +124,11 @@
return
user.electrocute_act(10, src)
+/obj/machinery/camera/singularity_pull(S, current_size)
+ if (status && current_size >= STAGE_FIVE) // If the singulo is strong enough to pull anchored objects and the camera is still active, turn off the camera as it gets ripped off the wall.
+ toggle_cam(null, 0)
+ ..()
+
/obj/machinery/camera/attackby(obj/item/W, mob/living/user, params)
var/msg = "You attach [W] into the assembly's inner circuits."
var/msg2 = "[src] already has that upgrade!"
@@ -268,9 +278,16 @@
status = !status
if(can_use())
GLOB.cameranet.addCamera(src)
+ if (isturf(loc))
+ myarea = get_area(src)
+ LAZYADD(myarea.cameras, src)
+ else
+ myarea = null
else
set_light(0)
GLOB.cameranet.removeCamera(src)
+ if (isarea(myarea))
+ LAZYREMOVE(myarea.cameras, src)
GLOB.cameranet.updateChunk(x, y, z)
var/change_msg = "deactivates"
if(status)
@@ -298,12 +315,12 @@
/obj/machinery/camera/proc/triggerCameraAlarm()
alarm_on = TRUE
- for(var/mob/living/silicon/S in GLOB.mob_list)
+ for(var/mob/living/silicon/S in GLOB.silicon_mobs)
S.triggerAlarm("Camera", get_area(src), list(src), src)
/obj/machinery/camera/proc/cancelCameraAlarm()
alarm_on = FALSE
- for(var/mob/living/silicon/S in GLOB.mob_list)
+ for(var/mob/living/silicon/S in GLOB.silicon_mobs)
S.cancelAlarm("Camera", get_area(src), src)
/obj/machinery/camera/proc/can_use()
diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm
index 019d52fe86..6769244335 100644
--- a/code/game/machinery/computer/station_alert.dm
+++ b/code/game/machinery/computer/station_alert.dm
@@ -1,85 +1,87 @@
-/obj/machinery/computer/station_alert
- name = "station alert console"
- desc = "Used to access the station's automated alert system."
- icon_screen = "alert:0"
- icon_keyboard = "atmos_key"
- circuit = /obj/item/circuitboard/computer/stationalert
- var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
-
- light_color = LIGHT_COLOR_CYAN
-
+/obj/machinery/computer/station_alert
+ name = "station alert console"
+ desc = "Used to access the station's automated alert system."
+ icon_screen = "alert:0"
+ icon_keyboard = "atmos_key"
+ circuit = /obj/item/circuitboard/computer/stationalert
+ var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
+
+ light_color = LIGHT_COLOR_CYAN
+
+/obj/machinery/computer/station_alert/Initialize()
+ . = ..()
+ GLOB.alert_consoles += src
+
+/obj/machinery/computer/station_alert/Destroy()
+ GLOB.alert_consoles -= src
+ return ..()
+
/obj/machinery/computer/station_alert/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "station_alert", name, 300, 500, master_ui, state)
- ui.open()
-
-/obj/machinery/computer/station_alert/ui_data(mob/user)
- var/list/data = list()
-
- data["alarms"] = list()
- for(var/class in alarms)
- data["alarms"][class] = list()
- for(var/area in alarms[class])
- data["alarms"][class] += area
-
- return data
-
-/obj/machinery/computer/station_alert/proc/triggerAlarm(class, area/A, O, obj/source)
- if(source.z != z)
- return
- if(stat & (BROKEN))
- return
-
- var/list/L = alarms[class]
- for(var/I in L)
- if (I == A.name)
- var/list/alarm = L[I]
- var/list/sources = alarm[3]
- if (!(source in sources))
- sources += source
- return 1
- var/obj/machinery/camera/C = null
- var/list/CL = null
- if(O && islist(O))
- CL = O
- if (CL.len == 1)
- C = CL[1]
- else if(O && istype(O, /obj/machinery/camera))
- C = O
- L[A.name] = list(A, (C ? C : O), list(source))
- return 1
-
-
-/obj/machinery/computer/station_alert/proc/cancelAlarm(class, area/A, obj/origin)
- if(stat & (BROKEN))
- return
- var/list/L = alarms[class]
- var/cleared = 0
- for (var/I in L)
- if (I == A.name)
- var/list/alarm = L[I]
- var/list/srcs = alarm[3]
- if (origin in srcs)
- srcs -= origin
- if (srcs.len == 0)
- cleared = 1
- L -= I
- return !cleared
-
-
-/obj/machinery/computer/station_alert/process()
- ..()
-
-/obj/machinery/computer/station_alert/update_icon()
- ..()
- if(stat & (NOPOWER|BROKEN))
- return
- var/active_alarms = FALSE
- for(var/cat in alarms)
- var/list/L = alarms[cat]
- if(L.len)
- active_alarms = TRUE
- if(active_alarms)
- add_overlay("alert:2")
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "station_alert", name, 300, 500, master_ui, state)
+ ui.open()
+
+/obj/machinery/computer/station_alert/ui_data(mob/user)
+ . = list()
+
+ .["alarms"] = list()
+ for(var/class in alarms)
+ .["alarms"][class] = list()
+ for(var/area in alarms[class])
+ .["alarms"][class] += area
+
+/obj/machinery/computer/station_alert/proc/triggerAlarm(class, area/A, O, obj/source)
+ if(source.z != z)
+ return
+ if(stat & (BROKEN))
+ return
+
+ var/list/L = alarms[class]
+ for(var/I in L)
+ if (I == A.name)
+ var/list/alarm = L[I]
+ var/list/sources = alarm[3]
+ if (!(source in sources))
+ sources += source
+ return 1
+ var/obj/machinery/camera/C = null
+ var/list/CL = null
+ if(O && islist(O))
+ CL = O
+ if (CL.len == 1)
+ C = CL[1]
+ else if(O && istype(O, /obj/machinery/camera))
+ C = O
+ L[A.name] = list(A, (C ? C : O), list(source))
+ return 1
+
+
+/obj/machinery/computer/station_alert/proc/cancelAlarm(class, area/A, obj/origin)
+ if(stat & (BROKEN))
+ return
+ var/list/L = alarms[class]
+ var/cleared = 0
+ for (var/I in L)
+ if (I == A.name)
+ var/list/alarm = L[I]
+ var/list/srcs = alarm[3]
+ if (origin in srcs)
+ srcs -= origin
+ if (srcs.len == 0)
+ cleared = 1
+ L -= I
+ return !cleared
+
+/obj/machinery/computer/station_alert/update_icon()
+ ..()
+ if(stat & (NOPOWER|BROKEN))
+ return
+ var/active_alarms = FALSE
+ for(var/cat in alarms)
+ var/list/L = alarms[cat]
+ if(L.len)
+ active_alarms = TRUE
+ if(active_alarms)
+ add_overlay("alert:2")
diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm
index 83d51bae0c..39df6f409e 100644
--- a/code/game/machinery/firealarm.dm
+++ b/code/game/machinery/firealarm.dm
@@ -1,3 +1,5 @@
+#define FIREALARM_COOLDOWN 67 // Chosen fairly arbitrarily, it is the length of the audio in FireAlarm.ogg. The actual track length is 7 seconds 8ms but but the audio stops at 6s 700ms
+
/obj/item/electronics/firealarm
name = "fire alarm electronics"
desc = "A fire alarm circuit. Can handle heat levels up to 40 degrees celsius."
@@ -25,7 +27,8 @@
var/detecting = 1
var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
resistance_flags = FIRE_PROOF
-
+ var/last_alarm = 0
+ var/area/myarea = null
/obj/machinery/firealarm/New(loc, dir, building)
..()
@@ -37,6 +40,12 @@
pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0
update_icon()
+ myarea = get_area(src)
+ LAZYADD(myarea.firealarms, src)
+
+/obj/machinery/firealarm/Destroy()
+ LAZYREMOVE(myarea.firealarms, src)
+ return ..()
/obj/machinery/firealarm/power_change()
..()
@@ -87,29 +96,24 @@
playsound(src, "sparks", 50, 1)
/obj/machinery/firealarm/temperature_expose(datum/gas_mixture/air, temperature, volume)
- if(!emagged && detecting && !stat && (temperature > T0C + 200 || temperature < BODYTEMP_COLD_DAMAGE_LIMIT))
+ if((temperature > T0C + 200 || temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && (last_alarm+FIREALARM_COOLDOWN < world.time) && !emagged && detecting && !stat)
alarm()
..()
/obj/machinery/firealarm/proc/alarm()
- if(!is_operational())
+ if(!is_operational() && (last_alarm+FIREALARM_COOLDOWN < world.time))
return
+ last_alarm = world.time
var/area/A = get_area(src)
A.firealert(src)
playsound(src.loc, 'goon/sound/machinery/FireAlarm.ogg', 75)
-/obj/machinery/firealarm/proc/alarm_in(time)
- addtimer(CALLBACK(src, .proc/alarm), time)
-
/obj/machinery/firealarm/proc/reset()
if(!is_operational())
return
var/area/A = get_area(src)
A.firereset(src)
-/obj/machinery/firealarm/proc/reset_in(time)
- addtimer(CALLBACK(src, .proc/reset), time)
-
/obj/machinery/firealarm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
@@ -248,8 +252,14 @@
if(prob(33))
alarm()
+/obj/machinery/firealarm/singularity_pull(S, current_size)
+ if (current_size >= STAGE_FIVE) // If the singulo is strong enough to pull anchored objects, the fire alarm experiences integrity failure
+ deconstruct()
+ ..()
+
/obj/machinery/firealarm/obj_break(damage_flag)
if(!(stat & BROKEN) && !(flags_1 & NODECONSTRUCT_1) && buildstage != 0) //can't break the electronics if there isn't any inside.
+ LAZYREMOVE(myarea.firealarms, src)
stat |= BROKEN
update_icon()
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index a8eb8ad12b..f7ee4ac29a 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -80,7 +80,7 @@
/mob/living/simple_animal/drone/Initialize()
. = ..()
-
+ GLOB.drones_list += src
access_card = new /obj/item/card/id(src)
var/datum/job/captain/C = new /datum/job/captain
access_card.access = C.get_access()
@@ -124,6 +124,7 @@
holder.icon_state = "hudstat"
/mob/living/simple_animal/drone/Destroy()
+ GLOB.drones_list -= src
qdel(access_card) //Otherwise it ends up on the floor!
return ..()