mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-26 22:50:26 +01:00
Redoes how alarms are handled, moves their behavior to datums (#60060)
* Adds in a set of datums to support sending, listening and storing alerts In contrast to the old system, we now store a list of send alerts on the listener, rather then the area itself. This makes clearing "our" alerts on destroy not a massive headache. In addition, we now use a direct ref to the area's cameras list and signals to prevent camera hard deletes. This, combined with the aformentioned ability to clear, virtually eliminates hard deletes sourced from alerts caused by strange senarios like the alert source moving its tile. * Converts areas to the system, of note is the fact that areas no longer store a bool that determins if an alert for power or atmos has been sent, that's instead handled by the alert sender datum. This means the sources list on alert listeners actually means something additionally, in order to prevent dumbassery with fire alarms since they're area based, fire alerts are sent by an alert handler on the area itself
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
//A set of defines to be used by the alarm datums
|
||||
///Sent by air alarms, indecates something wrong with thier attached atmosphere
|
||||
#define ALARM_ATMOS "Atmosphere"
|
||||
///Sent by fire alarms when they are toggled
|
||||
#define ALARM_FIRE "Fire"
|
||||
///Sent by apcs when their power starts to fail
|
||||
#define ALARM_POWER "Power"
|
||||
///Sent by cameras when they're disabled in some manner
|
||||
#define ALARM_CAMERA "Camera"
|
||||
///Sent by display cases when they're broken into
|
||||
#define ALARM_BURGLAR "Burglar"
|
||||
///Sent by motion detecting cameras when they well, detect motion
|
||||
#define ALARM_MOTION "Motion"
|
||||
@@ -49,6 +49,10 @@
|
||||
#define COMSIG_WEATHER_START(event_type) "!weather_start [event_type]"
|
||||
#define COMSIG_WEATHER_WINDDOWN(event_type) "!weather_winddown [event_type]"
|
||||
#define COMSIG_WEATHER_END(event_type) "!weather_end [event_type]"
|
||||
/// An alarm of some form was sent (datum/alarm_handler/source, alarm_type, area/source_area)
|
||||
#define COMSIG_ALARM_FIRE(alarm_type) "!alarm_fire [alarm_type]"
|
||||
/// An alarm of some form was cleared (datum/alarm_handler/source, alarm_type, area/source_area)
|
||||
#define COMSIG_ALARM_CLEAR(alarm_type) "!alarm_clear [alarm_type]"
|
||||
|
||||
/// signals from globally accessible objects
|
||||
|
||||
@@ -1381,6 +1385,11 @@
|
||||
/// Called on the merger after finishing a refresh: (list/leaving_members, list/joining_members)
|
||||
#define COMSIG_MERGER_REFRESH_COMPLETE "comsig_merger_refresh_complete"
|
||||
|
||||
// Alarm listener datum signals
|
||||
///Sent when an alarm is fired (alarm, area/source_area)
|
||||
#define COMSIG_ALARM_TRIGGERED "comsig_alarm_triggered"
|
||||
///Send when an alarm source is cleared (alarm_type, area/source_area)
|
||||
#define COMSIG_ALARM_CLEARED "comsig_alarm_clear"
|
||||
// Vacuum signals
|
||||
/// Called on a bag being attached to a vacuum parent
|
||||
#define COMSIG_VACUUM_BAG_ATTACH "comsig_vacuum_bag_attach"
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
//This files deals with the generic sending and receiving of "alarms"
|
||||
//This is a somewhat blanket term, it covers things like fire/power/atmos alarms, along with some oddballs
|
||||
//Side effect of how the system is used, these are mostly things that are of interest to ais and borgs
|
||||
//Though it could easily be expanded to cover other senders/revievers
|
||||
//The system as a whole differs from reading off a global list in a few ways.
|
||||
//In that A, it allows us to send cameras for ais/borgs/potentially others to jump to
|
||||
//And B, it's not like we're giving you all the alarms that have been sent, because of the seperate listing for each reviever
|
||||
//You only recieve alarms sent after you start to listen
|
||||
//Also of note, due to an optimzation done on areas, one alarm handler will only ever send one "on" or "off" alarm
|
||||
//So the whole only receving stuff sent post creation thing actually matters
|
||||
//Honestly I'm not sure how much of this is a feature, and how much is just old code
|
||||
//But I'm leaving it how I found it
|
||||
|
||||
///Represents a single source of alarms, one alarm handler will only ever count for one alarm per listener
|
||||
/datum/alarm_handler
|
||||
///A list of alarm type -> list of areas we currently have alarms in
|
||||
var/list/sent_alarms = list()
|
||||
///Our source atom
|
||||
var/atom/source_atom
|
||||
|
||||
/datum/alarm_handler/New(atom/source_atom)
|
||||
if(istype(source_atom))
|
||||
src.source_atom = source_atom
|
||||
else
|
||||
var/source_type = (istype(source_atom, /datum)) ? source_atom.type : ""
|
||||
stack_trace("a non atom was passed into alarm_handler! [source_atom] [source_type]")
|
||||
return ..()
|
||||
|
||||
/datum/alarm_handler/Destroy()
|
||||
for(var/alarm_type in sent_alarms)
|
||||
for(var/area/area_to_clear as anything in sent_alarms[alarm_type])
|
||||
//Yeet all connected alarms
|
||||
clear_alarm_from_area(alarm_type, area_to_clear)
|
||||
source_atom = null
|
||||
return ..()
|
||||
|
||||
///Sends an alarm to any interested things, does some checks to prevent unneeded work
|
||||
///Important to note is that source_atom is not held as a ref, we're used as a proxy to prevent hard deletes
|
||||
///optional_camera should only be used when you have one camera you want to pass along to alarm listeners, most of the time you should have no use for it
|
||||
/datum/alarm_handler/proc/send_alarm(alarm_type, atom/use_as_source_atom, optional_camera)
|
||||
if(!use_as_source_atom)
|
||||
use_as_source_atom = source_atom
|
||||
if(!use_as_source_atom)
|
||||
return
|
||||
|
||||
var/area/our_area = get_area(use_as_source_atom)
|
||||
var/our_z_level = use_as_source_atom.z
|
||||
|
||||
if (our_area.area_flags & NO_ALERTS)
|
||||
return FALSE
|
||||
|
||||
var/list/existing_alarms = sent_alarms[alarm_type]
|
||||
if(existing_alarms)
|
||||
if(our_area in existing_alarms)
|
||||
return FALSE
|
||||
else
|
||||
sent_alarms[alarm_type] = list()
|
||||
existing_alarms = sent_alarms[alarm_type]
|
||||
|
||||
existing_alarms += our_area
|
||||
|
||||
our_area.active_alarms[alarm_type] += 1
|
||||
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_ALARM_FIRE(alarm_type), src, alarm_type, our_area, our_z_level, optional_camera)
|
||||
|
||||
return TRUE
|
||||
|
||||
///Clears an alarm from any interested listeners
|
||||
/datum/alarm_handler/proc/clear_alarm(alarm_type, use_as_source_atom)
|
||||
SIGNAL_HANDLER
|
||||
if(!use_as_source_atom)
|
||||
use_as_source_atom = source_atom
|
||||
if(!use_as_source_atom)
|
||||
return
|
||||
|
||||
return clear_alarm_from_area(alarm_type, get_area(use_as_source_atom))
|
||||
|
||||
///Exists so we can request that the alarms from an area are cleared, even if our source atom is no longer in that area
|
||||
/datum/alarm_handler/proc/clear_alarm_from_area(alarm_type, area/our_area)
|
||||
if (our_area.area_flags & NO_ALERTS)
|
||||
return FALSE
|
||||
|
||||
var/list/existing_alarms = sent_alarms[alarm_type]
|
||||
if(!existing_alarms)
|
||||
return FALSE
|
||||
|
||||
if(!(our_area in existing_alarms))
|
||||
return FALSE
|
||||
|
||||
existing_alarms -= our_area
|
||||
if(!length(existing_alarms))
|
||||
sent_alarms -= alarm_type
|
||||
|
||||
our_area.active_alarms[alarm_type] -= 1
|
||||
if(!length(our_area.active_alarms))
|
||||
our_area.active_alarms -= alarm_type
|
||||
|
||||
SEND_GLOBAL_SIGNAL(COMSIG_ALARM_CLEAR(alarm_type), src, alarm_type, our_area)
|
||||
return TRUE
|
||||
|
||||
/datum/alarm_listener
|
||||
///List of valid source z levels, ignored if null
|
||||
var/list/allowed_z_levels
|
||||
///List of allowed areas. if this is null it's ignored
|
||||
var/list/allowed_areas
|
||||
|
||||
///List of alarm type -> list of area name -> list(area, ref to area's cameras, list(sources))
|
||||
var/list/alarms = list()
|
||||
///Should we allow alarm changes to go through or not
|
||||
var/accepting_alarm_changes = TRUE
|
||||
|
||||
///Accepts a list of alarm types to pay attention to, a list of valid z levels, and a list of valid areas. areas and zlevels are ignored if null
|
||||
/datum/alarm_listener/New(alarms_to_listen_for, allowed_z_levels, allowed_areas)
|
||||
src.allowed_z_levels = allowed_z_levels
|
||||
src.allowed_areas = allowed_areas
|
||||
for(var/alarm_type in alarms_to_listen_for)
|
||||
RegisterSignal(SSdcs, COMSIG_ALARM_FIRE(alarm_type), .proc/add_alarm)
|
||||
RegisterSignal(SSdcs, COMSIG_ALARM_CLEAR(alarm_type), .proc/clear_alarm)
|
||||
|
||||
return ..()
|
||||
|
||||
///Adds an alarm to our alarms list, you shouldn't be calling this manually
|
||||
///It should all be handled by the signal listening we do, unless you want to only send an alarm to one listener
|
||||
/datum/alarm_listener/proc/add_alarm(datum/source, datum/alarm_handler/handler, alarm_type, area/source_area, source_z, optional_camera)
|
||||
if (!accepting_alarm_changes)
|
||||
return
|
||||
|
||||
if(allowed_z_levels && !(source_z in allowed_z_levels))
|
||||
return
|
||||
|
||||
if(allowed_areas && !(source_area.type in allowed_areas))
|
||||
return
|
||||
|
||||
var/list/alarms_of_our_type = alarms[alarm_type]
|
||||
if(!alarms_of_our_type)
|
||||
alarms[alarm_type] = list()
|
||||
alarms_of_our_type = alarms[alarm_type]
|
||||
|
||||
if(alarms_of_our_type[source_area.name])
|
||||
var/list/alarm = alarms_of_our_type[source_area.name]
|
||||
var/list/sources = alarm[3]
|
||||
sources |= handler
|
||||
//Return if a source already exists, we don't want to send a signal or add a new entry
|
||||
return
|
||||
|
||||
//We normally directly pass in a ref to the area's camera's list to prevent hanging refs
|
||||
var/list/cameras = source_area.cameras
|
||||
if(optional_camera)
|
||||
cameras = list(optional_camera) // This will cause harddels, so we need to clear manually
|
||||
RegisterSignal(optional_camera, COMSIG_PARENT_QDELETING, .proc/clear_camera_ref, override = TRUE) //It's just fine to override, cause we clear all refs in the proc
|
||||
|
||||
//This does mean that only the first alarm of that camera type in the area will send a ping, but jesus what else can ya do
|
||||
alarms_of_our_type[source_area.name] = list(source_area, cameras, list(handler))
|
||||
SEND_SIGNAL(src, COMSIG_ALARM_TRIGGERED, alarm_type, source_area)
|
||||
|
||||
///Removes an alarm to our alarms list, you probably shouldn't be calling this manually
|
||||
///It should all be handled by the signal listening we do, unless you want to only remove an alarm to one listener
|
||||
/datum/alarm_listener/proc/clear_alarm(datum/source, datum/alarm_handler/handler, alarm_type, area/source_area)
|
||||
if(!accepting_alarm_changes)
|
||||
return
|
||||
|
||||
var/list/alarms_of_our_type = alarms[alarm_type]
|
||||
|
||||
if(!alarms_of_our_type)
|
||||
return
|
||||
|
||||
if(!alarms_of_our_type[source_area.name])
|
||||
return
|
||||
|
||||
var/list/alarm = alarms_of_our_type[source_area.name]
|
||||
var/list/sources = alarm[3]
|
||||
sources -= handler
|
||||
|
||||
if (length(sources))
|
||||
return //Return if there's still sources left, no sense clearing the list or bothering anyone about it
|
||||
|
||||
alarms_of_our_type -= source_area.name
|
||||
SEND_SIGNAL(src, COMSIG_ALARM_CLEARED, alarm_type, source_area)
|
||||
|
||||
///Does what it says on the tin, exists for signal hooking
|
||||
/datum/alarm_listener/proc/prevent_alarm_changes()
|
||||
SIGNAL_HANDLER
|
||||
accepting_alarm_changes = FALSE
|
||||
|
||||
///Does what it says on the tin, exists for signal hooking
|
||||
/datum/alarm_listener/proc/allow_alarm_changes()
|
||||
SIGNAL_HANDLER
|
||||
accepting_alarm_changes = TRUE
|
||||
|
||||
///Used to manually clear camera refs if one is ref'd directly
|
||||
/datum/alarm_listener/proc/clear_camera_ref(obj/machinery/camera/source)
|
||||
SIGNAL_HANDLER
|
||||
var/list/alarms_cache = alarms //Cache for sonic speec
|
||||
for(var/alarm_type in alarms_cache)
|
||||
var/list/alarms_of_type = alarms_cache[alarm_type] //Sonic cache speed forads
|
||||
for(var/area_name as anything in alarms_of_type)
|
||||
var/list/alarm_packet = alarms_of_type[area_name]
|
||||
var/list/cameras = alarm_packet[2]
|
||||
cameras -= source // REF FOUND AND CLEARED BOYSSSS
|
||||
@@ -48,8 +48,7 @@
|
||||
A.mode = 1 // AALARM_MODE_SCRUB
|
||||
A.apply_mode(usr)
|
||||
if(WIRE_ALARM) // Clear alarms.
|
||||
var/area/AA = get_area(A)
|
||||
if(AA.atmosalert(FALSE, holder))
|
||||
if(A.alarm_manager.clear_alarm(ALARM_ATMOS))
|
||||
A.post_alert(0)
|
||||
A.update_appearance()
|
||||
|
||||
@@ -70,7 +69,6 @@
|
||||
A.mode = 3 // AALARM_MODE_PANIC
|
||||
A.apply_mode(usr)
|
||||
if(WIRE_ALARM) // Post alarm.
|
||||
var/area/AA = get_area(A)
|
||||
if(AA.atmosalert(TRUE, holder))
|
||||
if(A.alarm_manager.send_alarm(ALARM_ATMOS))
|
||||
A.post_alert(2)
|
||||
A.update_appearance()
|
||||
|
||||
+11
-129
@@ -19,9 +19,11 @@
|
||||
var/fire = FALSE
|
||||
///How many fire alarm sources do we have?
|
||||
var/triggered_firealarms = 0
|
||||
///Whether there is an atmos alarm in this area
|
||||
var/atmosalm = FALSE
|
||||
var/poweralm = FALSE
|
||||
///Alarm type to count of sources. Not usable for ^ because we handle fires differently
|
||||
var/list/active_alarms = list()
|
||||
///We use this just for fire alarms, because they're area based right now so one alarm going poof shouldn't prevent you from clearing your alarms listing
|
||||
var/datum/alarm_handler/alarm_manager
|
||||
|
||||
var/lightswitch = TRUE
|
||||
|
||||
/// All beauty in this area combined, only includes indoor area.
|
||||
@@ -133,6 +135,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
if (area_flags & UNIQUE_AREA)
|
||||
GLOB.areas_by_type[type] = src
|
||||
power_usage = new /list(AREA_USAGE_LEN) // Some atoms would like to use power in Initialize()
|
||||
alarm_manager = new(src) // just in case
|
||||
return ..()
|
||||
|
||||
/*
|
||||
@@ -231,88 +234,9 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
GLOB.areas_by_type[type] = null
|
||||
GLOB.sortedAreas -= src
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
QDEL_NULL(alarm_manager)
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Generate a power alert for this area
|
||||
*
|
||||
* Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
|
||||
*/
|
||||
/area/proc/poweralert(state, obj/source)
|
||||
if (area_flags & NO_ALERTS)
|
||||
return
|
||||
if (state != poweralm)
|
||||
poweralm = state
|
||||
if(istype(source)) //Only report power alarms on the z-level where the source is located.
|
||||
for (var/item in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/aiPlayer = item
|
||||
if (!state)
|
||||
aiPlayer.cancelAlarm("Power", src, source)
|
||||
else
|
||||
aiPlayer.triggerAlarm("Power", src, cameras, source)
|
||||
|
||||
for (var/item in GLOB.alert_consoles)
|
||||
var/obj/machinery/computer/station_alert/a = item
|
||||
if(!state)
|
||||
a.cancelAlarm("Power", src, source)
|
||||
else
|
||||
a.triggerAlarm("Power", src, cameras, source)
|
||||
|
||||
for (var/item in GLOB.drones_list)
|
||||
var/mob/living/simple_animal/drone/D = item
|
||||
if(!state)
|
||||
D.cancelAlarm("Power", src, source)
|
||||
else
|
||||
D.triggerAlarm("Power", src, cameras, source)
|
||||
for(var/item in GLOB.alarmdisplay)
|
||||
var/datum/computer_file/program/alarm_monitor/p = item
|
||||
if(!state)
|
||||
p.cancelAlarm("Power", src, source)
|
||||
else
|
||||
p.triggerAlarm("Power", src, cameras, source)
|
||||
|
||||
/**
|
||||
* Generate an atmospheric alert for this area
|
||||
*
|
||||
* Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
|
||||
*/
|
||||
/area/proc/atmosalert(isdangerous, obj/source)
|
||||
if (area_flags & NO_ALERTS)
|
||||
return
|
||||
if(isdangerous != atmosalm)
|
||||
if(isdangerous)
|
||||
|
||||
for (var/item in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/aiPlayer = item
|
||||
aiPlayer.triggerAlarm("Atmosphere", src, cameras, source)
|
||||
for (var/item in GLOB.alert_consoles)
|
||||
var/obj/machinery/computer/station_alert/a = item
|
||||
a.triggerAlarm("Atmosphere", src, cameras, source)
|
||||
for (var/item in GLOB.drones_list)
|
||||
var/mob/living/simple_animal/drone/D = item
|
||||
D.triggerAlarm("Atmosphere", src, cameras, source)
|
||||
for(var/item in GLOB.alarmdisplay)
|
||||
var/datum/computer_file/program/alarm_monitor/p = item
|
||||
p.triggerAlarm("Atmosphere", src, cameras, source)
|
||||
|
||||
else
|
||||
for (var/item in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/aiPlayer = item
|
||||
aiPlayer.cancelAlarm("Atmosphere", src, source)
|
||||
for (var/item in GLOB.alert_consoles)
|
||||
var/obj/machinery/computer/station_alert/a = item
|
||||
a.cancelAlarm("Atmosphere", src, source)
|
||||
for (var/item in GLOB.drones_list)
|
||||
var/mob/living/simple_animal/drone/D = item
|
||||
D.cancelAlarm("Atmosphere", src, source)
|
||||
for(var/item in GLOB.alarmdisplay)
|
||||
var/datum/computer_file/program/alarm_monitor/p = item
|
||||
p.cancelAlarm("Atmosphere", src, source)
|
||||
|
||||
atmosalm = isdangerous
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Try to close all the firedoors in the area
|
||||
*/
|
||||
@@ -350,19 +274,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
for(var/item in firealarms)
|
||||
var/obj/machinery/firealarm/F = item
|
||||
F.update_appearance()
|
||||
if (!(area_flags & NO_ALERTS)) //Check here instead at the start of the proc so that fire alarms can still work locally even in areas that don't send alerts
|
||||
for (var/item in GLOB.alert_consoles)
|
||||
var/obj/machinery/computer/station_alert/a = item
|
||||
a.triggerAlarm("Fire", src, cameras, source)
|
||||
for (var/item in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/aiPlayer = item
|
||||
aiPlayer.triggerAlarm("Fire", src, cameras, source)
|
||||
for (var/item in GLOB.drones_list)
|
||||
var/mob/living/simple_animal/drone/D = item
|
||||
D.triggerAlarm("Fire", src, cameras, source)
|
||||
for(var/item in GLOB.alarmdisplay)
|
||||
var/datum/computer_file/program/alarm_monitor/p = item
|
||||
p.triggerAlarm("Fire", src, cameras, source)
|
||||
alarm_manager.send_alarm(ALARM_FIRE, source)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/**
|
||||
@@ -391,33 +303,9 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
for(var/item in firealarms)
|
||||
var/obj/machinery/firealarm/F = item
|
||||
F.update_appearance()
|
||||
if (!(area_flags & NO_ALERTS)) //Check here instead at the start of the proc so that fire alarms can still work locally even in areas that don't send alerts
|
||||
for (var/item in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/aiPlayer = item
|
||||
aiPlayer.cancelAlarm("Fire", src, source)
|
||||
for (var/item in GLOB.alert_consoles)
|
||||
var/obj/machinery/computer/station_alert/a = item
|
||||
a.cancelAlarm("Fire", src, source)
|
||||
for (var/item in GLOB.drones_list)
|
||||
var/mob/living/simple_animal/drone/D = item
|
||||
D.cancelAlarm("Fire", src, source)
|
||||
for(var/item in GLOB.alarmdisplay)
|
||||
var/datum/computer_file/program/alarm_monitor/p = item
|
||||
p.cancelAlarm("Fire", src, source)
|
||||
alarm_manager.clear_alarm(ALARM_FIRE, source)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
///Get rid of any dangling camera refs
|
||||
/area/proc/clear_camera(obj/machinery/camera/cam)
|
||||
LAZYREMOVE(cameras, cam)
|
||||
for (var/mob/living/silicon/aiPlayer as anything in GLOB.silicon_mobs)
|
||||
aiPlayer.freeCamera(src, cam)
|
||||
for (var/obj/machinery/computer/station_alert/comp as anything in GLOB.alert_consoles)
|
||||
comp.freeCamera(src, cam)
|
||||
for (var/mob/living/simple_animal/drone/drone_on as anything in GLOB.drones_list)
|
||||
drone_on.freeCamera(src, cam)
|
||||
for(var/datum/computer_file/program/alarm_monitor/monitor as anything in GLOB.alarmdisplay)
|
||||
monitor.freeCamera(src, cam)
|
||||
|
||||
/**
|
||||
* If 100 ticks has elapsed, toggle all the firedoors closed again
|
||||
*/
|
||||
@@ -451,14 +339,8 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
//Trigger alarm effect
|
||||
set_fire_alarm_effect()
|
||||
//Lockdown airlocks
|
||||
for(var/obj/machinery/door/DOOR in src)
|
||||
close_and_lock_door(DOOR)
|
||||
|
||||
for (var/i in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/SILICON = i
|
||||
if(SILICON.triggerAlarm("Burglar", src, cameras, trigger))
|
||||
//Cancel silicon alert after 1 minute
|
||||
addtimer(CALLBACK(SILICON, /mob/living/silicon.proc/cancelAlarm,"Burglar",src,trigger), 600)
|
||||
for(var/obj/machinery/door/door in src)
|
||||
close_and_lock_door(door)
|
||||
|
||||
/**
|
||||
* Trigger the fire alarm visual affects in an area
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
var/upgrades = 0
|
||||
|
||||
var/internal_light = TRUE //Whether it can light up when an AI views it
|
||||
///Represents a signel source of camera alarms about movement or camera tampering
|
||||
var/datum/alarm_handler/alarm_manager
|
||||
|
||||
/obj/machinery/camera/preset/toxins //Bomb test site in space
|
||||
name = "Hardened Bomb-Test Camera"
|
||||
@@ -86,6 +88,8 @@
|
||||
else //this is handled by toggle_camera, so no need to update it twice.
|
||||
update_appearance()
|
||||
|
||||
alarm_manager = new(src)
|
||||
|
||||
/obj/machinery/camera/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
|
||||
for(var/i in network)
|
||||
network -= i
|
||||
@@ -106,7 +110,8 @@
|
||||
GLOB.cameranet.cameras -= src
|
||||
cancelCameraAlarm()
|
||||
if(isarea(myarea))
|
||||
myarea.clear_camera(src)
|
||||
LAZYREMOVE(myarea.cameras, src)
|
||||
QDEL_NULL(alarm_manager)
|
||||
QDEL_NULL(assembly_ref)
|
||||
if(bug)
|
||||
bug.bugged_cameras -= c_tag
|
||||
@@ -443,13 +448,11 @@
|
||||
|
||||
/obj/machinery/camera/proc/triggerCameraAlarm()
|
||||
alarm_on = TRUE
|
||||
for(var/mob/living/silicon/S in GLOB.silicon_mobs)
|
||||
S.triggerAlarm("Camera", get_area(src), list(src), src)
|
||||
alarm_manager.send_alarm(ALARM_CAMERA, src, src)
|
||||
|
||||
/obj/machinery/camera/proc/cancelCameraAlarm()
|
||||
alarm_on = FALSE
|
||||
for(var/mob/living/silicon/S in GLOB.silicon_mobs)
|
||||
S.cancelAlarm("Camera", get_area(src), src)
|
||||
alarm_manager.clear_alarm(ALARM_CAMERA)
|
||||
|
||||
/obj/machinery/camera/proc/can_use()
|
||||
if(!status)
|
||||
|
||||
@@ -51,20 +51,16 @@
|
||||
cancelAlarm()
|
||||
|
||||
/obj/machinery/camera/proc/cancelAlarm()
|
||||
if (detectTime == -1)
|
||||
for (var/i in GLOB.silicon_mobs)
|
||||
var/mob/living/silicon/aiPlayer = i
|
||||
if (status)
|
||||
aiPlayer.cancelAlarm("Motion", get_area(src), src)
|
||||
if (detectTime == -1 && status)
|
||||
alarm_manager.clear_alarm(ALARM_MOTION)
|
||||
detectTime = 0
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/camera/proc/triggerAlarm()
|
||||
if (!detectTime)
|
||||
return FALSE
|
||||
for (var/mob/living/silicon/aiPlayer in GLOB.player_list)
|
||||
if (status)
|
||||
aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src)
|
||||
if(status)
|
||||
if(alarm_manager.send_alarm(ALARM_MOTION, src, src))
|
||||
visible_message(span_warning("A red light flashes on the [src]!"))
|
||||
detectTime = -1
|
||||
return TRUE
|
||||
|
||||
@@ -4,16 +4,17 @@
|
||||
icon_screen = "alert:0"
|
||||
icon_keyboard = "atmos_key"
|
||||
circuit = /obj/item/circuitboard/computer/stationalert
|
||||
var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
|
||||
///Listens for alarms, provides the alarms list for our ui
|
||||
var/datum/alarm_listener/listener
|
||||
|
||||
light_color = LIGHT_COLOR_CYAN
|
||||
|
||||
/obj/machinery/computer/station_alert/Initialize()
|
||||
. = ..()
|
||||
GLOB.alert_consoles += src
|
||||
listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER), list(z))
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/station_alert/Destroy()
|
||||
GLOB.alert_consoles -= src
|
||||
QDEL_NULL(listener)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/station_alert/ui_interact(mob/user, datum/tgui/ui)
|
||||
@@ -26,78 +27,23 @@
|
||||
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
|
||||
var/list/alarms = listener.alarms
|
||||
for(var/alarm_type in alarms)
|
||||
data["alarms"][alarm_type] = list()
|
||||
for(var/area_name in alarms[alarm_type])
|
||||
data["alarms"][alarm_type] += area_name
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/station_alert/proc/triggerAlarm(class, area/home, cameras, obj/source)
|
||||
if(source.z != z)
|
||||
return
|
||||
if(machine_stat & (BROKEN))
|
||||
return
|
||||
|
||||
var/list/our_sort = alarms[class]
|
||||
for(var/areaname in our_sort)
|
||||
if (areaname == home.name)
|
||||
var/list/alarm = our_sort[areaname]
|
||||
var/list/sources = alarm[3]
|
||||
if (!(source in sources))
|
||||
sources += source
|
||||
return TRUE
|
||||
|
||||
var/obj/machinery/camera/cam = null
|
||||
var/list/our_cams = null
|
||||
if(cameras && islist(cameras))
|
||||
our_cams = cameras
|
||||
if (our_cams.len == 1)
|
||||
cam = our_cams[1]
|
||||
else if(cameras && istype(cameras, /obj/machinery/camera))
|
||||
cam = cameras
|
||||
our_sort[home.name] = list(home, (cam ? cam : cameras), list(source))
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/station_alert/proc/freeCamera(area/home, obj/machinery/camera/cam)
|
||||
for(var/class in alarms)
|
||||
var/our_area = alarms[class][home.name]
|
||||
if(!our_area)
|
||||
continue
|
||||
var/cams = our_area[2] //Get the cameras
|
||||
if(!cams)
|
||||
continue
|
||||
if(islist(cams))
|
||||
cams -= cam
|
||||
if(length(cams) == 1)
|
||||
our_area[2] = cams[1]
|
||||
else
|
||||
our_area[2] = null
|
||||
|
||||
/obj/machinery/computer/station_alert/proc/cancelAlarm(class, area/A, obj/origin)
|
||||
if(machine_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/on_set_machine_stat(old_value)
|
||||
if(machine_stat & BROKEN)
|
||||
listener.prevent_alarm_changes()
|
||||
else
|
||||
listener.allow_alarm_changes()
|
||||
|
||||
/obj/machinery/computer/station_alert/update_overlays()
|
||||
. = ..()
|
||||
if(machine_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)
|
||||
if(length(listener.alarms))
|
||||
. += "alert:2"
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
var/list/start_showpieces = list() //Takes sublists in the form of list("type" = /obj/item/bikehorn, "trophy_message" = "henk")
|
||||
var/trophy_message = ""
|
||||
var/glass_fix = TRUE
|
||||
///Represents a signel source of screaming when broken
|
||||
var/datum/alarm_handler/alarm_manager
|
||||
|
||||
/obj/structure/displaycase/Initialize()
|
||||
. = ..()
|
||||
@@ -32,6 +34,7 @@
|
||||
if(start_showpiece_type)
|
||||
showpiece = new start_showpiece_type (src)
|
||||
update_appearance()
|
||||
alarm_manager = new(src)
|
||||
|
||||
/obj/structure/displaycase/vv_edit_var(vname, vval)
|
||||
. = ..()
|
||||
@@ -49,6 +52,7 @@
|
||||
/obj/structure/displaycase/Destroy()
|
||||
QDEL_NULL(electronics)
|
||||
QDEL_NULL(showpiece)
|
||||
QDEL_NULL(alarm_manager)
|
||||
return ..()
|
||||
|
||||
/obj/structure/displaycase/examine(mob/user)
|
||||
@@ -98,6 +102,10 @@
|
||||
return
|
||||
var/area/alarmed = get_area(src)
|
||||
alarmed.burglaralert(src)
|
||||
|
||||
alarm_manager.send_alarm(ALARM_BURGLAR)
|
||||
addtimer(CALLBACK(alarm_manager, /datum/alarm_handler/proc/clear_alarm, ALARM_BURGLAR), 1 MINUTES)
|
||||
|
||||
playsound(src, 'sound/effects/alert.ogg', 50, TRUE)
|
||||
|
||||
/obj/structure/displaycase/update_overlays()
|
||||
@@ -122,7 +130,7 @@
|
||||
to_chat(user, span_notice("You [open ? "close":"open"] [src]."))
|
||||
toggle_lock(user)
|
||||
else
|
||||
to_chat(user, span_alert("Access denied."))
|
||||
to_chat(user, span_alert("Access denied."))
|
||||
else if(W.tool_behaviour == TOOL_WELDER && !user.combat_mode && !broken)
|
||||
if(obj_integrity < max_integrity)
|
||||
if(!W.tool_start_check(user, amount=5))
|
||||
|
||||
@@ -82,6 +82,8 @@
|
||||
var/frequency = FREQ_ATMOS_CONTROL
|
||||
var/alarm_frequency = FREQ_ATMOS_ALARMS
|
||||
var/datum/radio_frequency/radio_connection
|
||||
///Represents a signel source of atmos alarms, complains to all the listeners if one of our thresholds is violated
|
||||
var/datum/alarm_handler/alarm_manager
|
||||
|
||||
var/list/TLV = list( // Breathable air.
|
||||
"pressure" = new/datum/tlv(HAZARD_LOW_PRESSURE, WARNING_LOW_PRESSURE, WARNING_HIGH_PRESSURE, HAZARD_HIGH_PRESSURE), // kPa. Values are min2, min1, max1, max2
|
||||
@@ -227,14 +229,13 @@
|
||||
if(name == initial(name))
|
||||
name = "[get_area_name(src)] Air Alarm"
|
||||
|
||||
alarm_manager = new(src)
|
||||
update_appearance()
|
||||
|
||||
/obj/machinery/airalarm/Destroy()
|
||||
SSradio.remove_object(src, frequency)
|
||||
qdel(wires)
|
||||
wires = null
|
||||
var/area/ourarea = get_area(src)
|
||||
ourarea.atmosalert(FALSE, src)
|
||||
QDEL_NULL(wires)
|
||||
QDEL_NULL(alarm_manager)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/airalarm/Initialize(mapload)
|
||||
@@ -277,7 +278,7 @@
|
||||
)
|
||||
|
||||
var/area/A = get_area(src)
|
||||
data["atmos_alarm"] = A.atmosalm
|
||||
data["atmos_alarm"] = !!A.active_alarms[ALARM_ATMOS]
|
||||
data["fire_alarm"] = A.fire
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
@@ -447,13 +448,11 @@
|
||||
apply_mode(usr)
|
||||
. = TRUE
|
||||
if("alarm")
|
||||
var/area/A = get_area(src)
|
||||
if(A.atmosalert(TRUE, src))
|
||||
if(alarm_manager.send_alarm(ALARM_ATMOS))
|
||||
post_alert(2)
|
||||
. = TRUE
|
||||
if("reset")
|
||||
var/area/A = get_area(src)
|
||||
if(A.atmosalert(FALSE, src))
|
||||
if(alarm_manager.clear_alarm(ALARM_ATMOS))
|
||||
post_alert(0)
|
||||
. = TRUE
|
||||
update_appearance()
|
||||
@@ -659,8 +658,8 @@
|
||||
icon_state = "alarmp"
|
||||
return ..()
|
||||
|
||||
var/area/A = get_area(src)
|
||||
switch(max(danger_level, A.atmosalm))
|
||||
var/area/our_area = get_area(src)
|
||||
switch(max(danger_level, !!our_area.active_alarms[ALARM_ATMOS]))
|
||||
if(0)
|
||||
icon_state = "alarm0"
|
||||
if(1)
|
||||
@@ -734,8 +733,14 @@
|
||||
var/new_area_danger_level = 0
|
||||
for(var/obj/machinery/airalarm/AA in A)
|
||||
if (!(AA.machine_stat & (NOPOWER|BROKEN)) && !AA.shorted)
|
||||
new_area_danger_level = clamp(max(new_area_danger_level, AA.danger_level), 0,1)
|
||||
if(A.atmosalert(new_area_danger_level,src)) //if area was in normal state or if area was in alert state
|
||||
new_area_danger_level = clamp(max(new_area_danger_level, AA.danger_level), 0, 1)
|
||||
|
||||
var/did_anything_happen
|
||||
if(new_area_danger_level)
|
||||
did_anything_happen = alarm_manager.send_alarm(ALARM_ATMOS)
|
||||
else
|
||||
did_anything_happen = alarm_manager.clear_alarm(ALARM_ATMOS)
|
||||
if(did_anything_happen) //if something actually changed
|
||||
post_alert(new_area_danger_level)
|
||||
|
||||
update_appearance()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Look up levels[z].traits[trait]
|
||||
/// Look up levels[z].traits[trait]
|
||||
/datum/controller/subsystem/mapping/proc/level_trait(z, trait)
|
||||
if (!isnum(z) || z < 1)
|
||||
return null
|
||||
@@ -15,21 +15,21 @@
|
||||
return list()
|
||||
return default[z][DL_TRAITS][trait]
|
||||
|
||||
// Check if levels[z] has any of the specified traits
|
||||
/// Check if levels[z] has any of the specified traits
|
||||
/datum/controller/subsystem/mapping/proc/level_has_any_trait(z, list/traits)
|
||||
for (var/I in traits)
|
||||
if (level_trait(z, I))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Check if levels[z] has all of the specified traits
|
||||
/// Check if levels[z] has all of the specified traits
|
||||
/datum/controller/subsystem/mapping/proc/level_has_all_traits(z, list/traits)
|
||||
for (var/I in traits)
|
||||
if (!level_trait(z, I))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// Get a list of all z which have the specified trait
|
||||
/// Get a list of all z which have the specified trait
|
||||
/datum/controller/subsystem/mapping/proc/levels_by_trait(trait)
|
||||
. = list()
|
||||
var/list/_z_list = z_list
|
||||
@@ -38,7 +38,7 @@
|
||||
if (S.traits[trait])
|
||||
. += S.z_value
|
||||
|
||||
// Get a list of all z which have any of the specified traits
|
||||
/// Get a list of all z which have any of the specified traits
|
||||
/datum/controller/subsystem/mapping/proc/levels_by_any_trait(list/traits)
|
||||
. = list()
|
||||
var/list/_z_list = z_list
|
||||
@@ -49,7 +49,7 @@
|
||||
. += S.z_value
|
||||
break
|
||||
|
||||
// Attempt to get the turf below the provided one according to Z traits
|
||||
/// Attempt to get the turf below the provided one according to Z traits
|
||||
/datum/controller/subsystem/mapping/proc/get_turf_below(turf/T)
|
||||
if (!T)
|
||||
return
|
||||
@@ -58,7 +58,7 @@
|
||||
return
|
||||
return locate(T.x, T.y, T.z + offset)
|
||||
|
||||
// Attempt to get the turf above the provided one according to Z traits
|
||||
/// Attempt to get the turf above the provided one according to Z traits
|
||||
/datum/controller/subsystem/mapping/proc/get_turf_above(turf/T)
|
||||
if (!T)
|
||||
return
|
||||
@@ -67,7 +67,7 @@
|
||||
return
|
||||
return locate(T.x, T.y, T.z + offset)
|
||||
|
||||
// Prefer not to use this one too often
|
||||
/// Prefer not to use this one too often
|
||||
/datum/controller/subsystem/mapping/proc/get_station_center()
|
||||
var/station_z = levels_by_trait(ZTRAIT_STATION)[1]
|
||||
return locate(round(world.maxx * 0.5, 1), round(world.maxy * 0.5, 1), station_z)
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
var/aiRestorePowerRoutine = POWER_RESTORATION_OFF
|
||||
var/requires_power = POWER_REQ_ALL
|
||||
var/can_be_carded = TRUE
|
||||
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list())
|
||||
var/viewalerts = 0
|
||||
var/icon/holo_icon //Default is assigned when AI is created.
|
||||
var/obj/vehicle/sealed/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye.
|
||||
@@ -101,6 +100,8 @@
|
||||
var/atom/cam_prev
|
||||
|
||||
var/datum/robot_control/robot_control
|
||||
///Alarm listener datum, handes caring about alarm events and such
|
||||
var/datum/alarm_listener/listener
|
||||
///remember AI's last location
|
||||
var/atom/lastloc
|
||||
|
||||
@@ -176,6 +177,9 @@
|
||||
ADD_TRAIT(src, TRAIT_PULL_BLOCKED, ROUNDSTART_TRAIT)
|
||||
ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, ROUNDSTART_TRAIT)
|
||||
|
||||
listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER, ALARM_CAMERA, ALARM_BURGLAR, ALARM_MOTION), list(z))
|
||||
RegisterSignal(listener, COMSIG_ALARM_TRIGGERED, .proc/alarm_triggered)
|
||||
RegisterSignal(listener, COMSIG_ALARM_CLEARED, .proc/alarm_cleared)
|
||||
|
||||
/mob/living/silicon/ai/key_down(_key, client/user)
|
||||
if(findtext(_key, "numpad")) //if it's a numpad number, we can convert it to just the number
|
||||
@@ -209,6 +213,7 @@
|
||||
QDEL_NULL(doomsday_device)
|
||||
QDEL_NULL(robot_control)
|
||||
QDEL_NULL(aiMulti)
|
||||
QDEL_NULL(listener)
|
||||
malfhack = null
|
||||
current = null
|
||||
Bot = null
|
||||
@@ -268,12 +273,12 @@
|
||||
/mob/living/silicon/ai/get_status_tab_items()
|
||||
. = ..()
|
||||
if(stat != CONSCIOUS)
|
||||
. += text("Systems nonfunctional")
|
||||
. += "Systems nonfunctional"
|
||||
return
|
||||
. += text("System integrity: [(health + 100) * 0.5]%")
|
||||
. += "System integrity: [(health + 100) * 0.5]%"
|
||||
if(isturf(loc)) //only show if we're "in" a core
|
||||
. += text("Backup Power: [battery * 0.5]%")
|
||||
. += text("Connected cyborgs: [length(connected_robots)]")
|
||||
. += "Backup Power: [battery * 0.5]%"
|
||||
. += "Connected cyborgs: [length(connected_robots)]"
|
||||
for(var/r in connected_robots)
|
||||
var/mob/living/silicon/robot/connected_robot = r
|
||||
var/robot_status = "Nominal"
|
||||
@@ -284,19 +289,20 @@
|
||||
else if(!connected_robot.cell || connected_robot.cell.charge <= 0)
|
||||
robot_status = "DEPOWERED"
|
||||
//Name, Health, Battery, Model, Area, and Status! Everything an AI wants to know about its borgies!
|
||||
. += text("[connected_robot.name] | S.Integrity: [connected_robot.health]% | Cell: [connected_robot.cell ? "[connected_robot.cell.charge]/[connected_robot.cell.maxcharge]" : "Empty"] | \
|
||||
Model: [connected_robot.designation] | Loc: [get_area_name(connected_robot, TRUE)] | Status: [robot_status]")
|
||||
. += text("AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]") //Count of total AI shells
|
||||
. += "[connected_robot.name] | S.Integrity: [connected_robot.health]% | Cell: [connected_robot.cell ? "[connected_robot.cell.charge]/[connected_robot.cell.maxcharge]" : "Empty"] | \
|
||||
Model: [connected_robot.designation] | Loc: [get_area_name(connected_robot, TRUE)] | Status: [robot_status]"
|
||||
. += "AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]" //Count of total AI shells
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_alerts()
|
||||
var/dat = "<HEAD><TITLE>Current Station Alerts</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'></HEAD><BODY>\n"
|
||||
dat += "<A HREF='?src=[REF(src)];mach_close=aialerts'>Close</A><BR><BR>"
|
||||
for (var/cat in alarms)
|
||||
dat += text("<B>[]</B><BR>\n", cat)
|
||||
var/list/L = alarms[cat]
|
||||
if (L.len)
|
||||
for (var/alarm in L)
|
||||
var/list/alm = L[alarm]
|
||||
var/list/alarms = listener.alarms
|
||||
for (var/alarm_type in alarms)
|
||||
dat += "<B>[alarm_type]</B><BR>\n"
|
||||
var/list/alerts = alarms[alarm_type]
|
||||
if (length(alerts))
|
||||
for (var/alarm in alerts)
|
||||
var/list/alm = alerts[alarm]
|
||||
var/area/A = alm[1]
|
||||
var/C = alm[2]
|
||||
var/list/sources = alm[3]
|
||||
@@ -304,15 +310,15 @@
|
||||
if (C && istype(C, /list))
|
||||
var/dat2 = ""
|
||||
for (var/obj/machinery/camera/I in C)
|
||||
dat2 += text("[]<A HREF=?src=[REF(src)];switchcamera=[REF(I)]>[]</A>", (dat2=="") ? "" : " | ", I.c_tag)
|
||||
dat += text("-- [] ([])", A.name, (dat2!="") ? dat2 : "No Camera")
|
||||
dat2 += "[(dat2=="") ? "" : " | "]<A HREF=?src=[REF(src)];switchcamera=[REF(I)]>[I.c_tag]</A>"
|
||||
dat += "-- [A.name] ([(dat2!="") ? dat2 : "No Camera"])"
|
||||
else if (C && istype(C, /obj/machinery/camera))
|
||||
var/obj/machinery/camera/Ctmp = C
|
||||
dat += text("-- [] (<A HREF=?src=[REF(src)];switchcamera=[REF(C)]>[]</A>)", A.name, Ctmp.c_tag)
|
||||
dat += "-- [A.name] (<A HREF=?src=[REF(src)];switchcamera=[REF(C)]>[Ctmp.c_tag]</A>)"
|
||||
else
|
||||
dat += text("-- [] (No Camera)", A.name)
|
||||
dat += "-- [A.name] (No Camera)"
|
||||
if (sources.len > 1)
|
||||
dat += text("- [] sources", sources.len)
|
||||
dat += "- [sources.len] sources"
|
||||
dat += "</NOBR><BR>\n"
|
||||
else
|
||||
dat += "-- All Systems Nominal<BR>\n"
|
||||
@@ -414,7 +420,7 @@
|
||||
if (href_list["mach_close"])
|
||||
if (href_list["mach_close"] == "aialerts")
|
||||
viewalerts = 0
|
||||
var/t1 = text("window=[]", href_list["mach_close"])
|
||||
var/t1 = "window=[href_list["mach_close"]]"
|
||||
unset_machine()
|
||||
src << browse(null, t1)
|
||||
if (href_list["switchcamera"])
|
||||
@@ -538,77 +544,33 @@
|
||||
Bot.call_bot(src, waypoint)
|
||||
call_bot_cooldown = 0
|
||||
|
||||
/mob/living/silicon/ai/triggerAlarm(class, area/home, cameras, obj/source)
|
||||
if(source.z != z)
|
||||
return
|
||||
var/list/our_sort = alarms[class]
|
||||
for(var/areaname in our_sort)
|
||||
if (areaname == home.name)
|
||||
var/list/alarm = our_sort[areaname]
|
||||
var/list/sources = alarm[3]
|
||||
if (!(source in sources))
|
||||
sources += source
|
||||
return TRUE
|
||||
/mob/living/silicon/ai/proc/alarm_triggered(datum/source, alarm_type, area/source_area)
|
||||
SIGNAL_HANDLER
|
||||
var/list/cameras = source_area.cameras
|
||||
var/home_name = source_area.name
|
||||
|
||||
var/obj/machinery/camera/cam = null
|
||||
var/list/our_cams = null
|
||||
if(cameras && islist(cameras))
|
||||
our_cams = cameras
|
||||
if (our_cams.len == 1)
|
||||
cam = our_cams[1]
|
||||
else if(cameras && istype(cameras, /obj/machinery/camera))
|
||||
cam = cameras
|
||||
our_sort[home.name] = list(home, (cam ? cam : cameras), list(source))
|
||||
|
||||
if (cameras)
|
||||
if (cam?.can_use())
|
||||
queueAlarm("--- [class] alarm detected in [home.name]! (<A HREF=?src=[REF(src)];switchcamera=[REF(cam)]>[cam.c_tag]</A>)", class)
|
||||
else if (our_cams?.len)
|
||||
var/foo = 0
|
||||
var/dat2 = ""
|
||||
for (var/obj/machinery/camera/I in our_cams)
|
||||
dat2 += text("[]<A HREF=?src=[REF(src)];switchcamera=[REF(I)]>[]</A>", (!foo) ? "" : " | ", I.c_tag) //I'm not fixing this shit...
|
||||
foo = 1
|
||||
queueAlarm(text ("--- [] alarm detected in []! ([])", class, home.name, dat2), class)
|
||||
if (length(cameras))
|
||||
var/obj/machinery/camera/cam = cameras[1]
|
||||
if (cam.can_use())
|
||||
queueAlarm("--- [alarm_type] alarm detected in [home_name]! (<A HREF=?src=[REF(src)];switchcamera=[REF(cam)]>[cam.c_tag]</A>)", alarm_type)
|
||||
else
|
||||
queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, home.name), class)
|
||||
var/first_run = FALSE
|
||||
var/dat2 = ""
|
||||
for (var/obj/machinery/camera/camera as anything in cameras)
|
||||
dat2 += "[(!first_run) ? "" : " | "]<A HREF=?src=[REF(src)];switchcamera=[REF(camera)]>[camera.c_tag]</A>"
|
||||
first_run = TRUE
|
||||
queueAlarm("--- [alarm_type] alarm detected in [home_name]! ([dat2])", alarm_type)
|
||||
else
|
||||
queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, home.name), class)
|
||||
queueAlarm("--- [alarm_type] alarm detected in [home_name]! (No Camera)", alarm_type)
|
||||
if (viewalerts)
|
||||
ai_alerts()
|
||||
return 1
|
||||
|
||||
/mob/living/silicon/ai/freeCamera(area/home, obj/machinery/camera/cam)
|
||||
for(var/class in alarms)
|
||||
var/our_area = alarms[class][home.name]
|
||||
if(!our_area)
|
||||
continue
|
||||
var/cams = our_area[2] //Get the cameras
|
||||
if(!cams)
|
||||
continue
|
||||
if(islist(cams))
|
||||
cams -= cam
|
||||
if(length(cams) == 1)
|
||||
our_area[2] = cams[1]
|
||||
else
|
||||
our_area[2] = null
|
||||
|
||||
/mob/living/silicon/ai/cancelAlarm(class, area/A, obj/origin)
|
||||
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
|
||||
if (cleared)
|
||||
queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
|
||||
if (viewalerts) ai_alerts()
|
||||
return !cleared
|
||||
/mob/living/silicon/ai/proc/alarm_cleared(datum/source, alarm_type, area/source_area)
|
||||
SIGNAL_HANDLER
|
||||
queueAlarm("--- [alarm_type] alarm in [source_area.name] has been cleared.", alarm_type, 0)
|
||||
if(viewalerts)
|
||||
ai_alerts()
|
||||
|
||||
//Replaces /mob/living/silicon/ai/verb/change_network() in ai.dm & camera.dm
|
||||
//Adds in /mob/living/silicon/ai/proc/ai_network_change() instead
|
||||
|
||||
@@ -69,6 +69,12 @@
|
||||
diag_hud_set_borgcell()
|
||||
logevent("System brought online.")
|
||||
|
||||
listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER, ALARM_CAMERA, ALARM_BURGLAR, ALARM_MOTION), list(z))
|
||||
RegisterSignal(listener, COMSIG_ALARM_TRIGGERED, .proc/alarm_triggered)
|
||||
RegisterSignal(listener, COMSIG_ALARM_CLEARED, .proc/alarm_cleared)
|
||||
listener.RegisterSignal(src, COMSIG_LIVING_DEATH, /datum/alarm_listener/proc/prevent_alarm_changes)
|
||||
listener.RegisterSignal(src, COMSIG_LIVING_REVIVE, /datum/alarm_listener/proc/allow_alarm_changes)
|
||||
|
||||
/mob/living/silicon/robot/model/syndicate/Initialize()
|
||||
. = ..()
|
||||
laws = new /datum/ai_laws/syndicate_override()
|
||||
@@ -118,6 +124,7 @@
|
||||
QDEL_NULL(inv2)
|
||||
QDEL_NULL(inv3)
|
||||
QDEL_NULL(spark_system)
|
||||
QDEL_NULL(listener)
|
||||
cell = null
|
||||
return ..()
|
||||
|
||||
@@ -200,15 +207,16 @@
|
||||
|
||||
/mob/living/silicon/robot/proc/robot_alerts()
|
||||
var/dat = ""
|
||||
for (var/cat in alarms)
|
||||
dat += text("<B>[cat]</B><BR>\n")
|
||||
var/list/L = alarms[cat]
|
||||
if (L.len)
|
||||
for (var/alarm in L)
|
||||
var/list/alm = L[alarm]
|
||||
var/list/alarms = listener.alarms
|
||||
for (var/alarm_type in alarms)
|
||||
dat += "<B>[alarm_type]</B><BR>\n"
|
||||
var/list/alerts = alarms[alarm_type]
|
||||
if (length(alerts))
|
||||
for (var/alarm in alerts)
|
||||
var/list/alm = alerts[alarm]
|
||||
var/area/A = alm[1]
|
||||
dat += "<NOBR>"
|
||||
dat += text("-- [A.name]")
|
||||
dat += "-- [A.name]"
|
||||
dat += "</NOBR><BR>\n"
|
||||
else
|
||||
dat += "-- All Systems Nominal<BR>\n"
|
||||
@@ -251,7 +259,7 @@
|
||||
if(cell)
|
||||
. += "Charge Left: [cell.charge]/[cell.maxcharge]"
|
||||
else
|
||||
. += text("No Cell Inserted!")
|
||||
. += "No Cell Inserted!"
|
||||
|
||||
if(model)
|
||||
for(var/datum/robot_energy_storage/st in model.storages)
|
||||
@@ -259,63 +267,13 @@
|
||||
if(connected_ai)
|
||||
. += "Master AI: [connected_ai.name]"
|
||||
|
||||
/mob/living/silicon/robot/proc/alarm_triggered(datum/source, alarm_type, area/source_area)
|
||||
SIGNAL_HANDLER
|
||||
queueAlarm("--- [alarm_type] alarm detected in [source_area.name]!", alarm_type)
|
||||
|
||||
/mob/living/silicon/robot/triggerAlarm(class, area/home, cameras, obj/source)
|
||||
if(source.z != z)
|
||||
return
|
||||
if(stat == DEAD)
|
||||
return TRUE
|
||||
var/list/our_sort = alarms[class]
|
||||
for(var/areaname in our_sort)
|
||||
if (areaname == home.name)
|
||||
var/list/alarm = our_sort[areaname]
|
||||
var/list/sources = alarm[3]
|
||||
if (!(source in sources))
|
||||
sources += source
|
||||
return TRUE
|
||||
|
||||
var/obj/machinery/camera/cam = null
|
||||
var/list/our_cams = null
|
||||
if(cameras && islist(cameras))
|
||||
our_cams = cameras
|
||||
if (our_cams.len == 1)
|
||||
cam = our_cams[1]
|
||||
else if(cameras && istype(cameras, /obj/machinery/camera))
|
||||
cam = cameras
|
||||
our_sort[home.name] = list(home, (cam ? cam : cameras), list(source))
|
||||
queueAlarm(text("--- [class] alarm detected in [home.name]!"), class)
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/robot/freeCamera(area/home, obj/machinery/camera/cam)
|
||||
for(var/class in alarms)
|
||||
var/our_area = alarms[class][home.name]
|
||||
if(!our_area)
|
||||
continue
|
||||
var/cams = our_area[2] //Get the cameras
|
||||
if(!cams)
|
||||
continue
|
||||
if(islist(cams))
|
||||
cams -= cam
|
||||
if(length(cams) == 1)
|
||||
our_area[2] = cams[1]
|
||||
else
|
||||
our_area[2] = null
|
||||
|
||||
/mob/living/silicon/robot/cancelAlarm(class, area/A, obj/origin)
|
||||
var/list/L = alarms[class]
|
||||
var/cleared = FALSE
|
||||
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 = TRUE
|
||||
L -= I
|
||||
if (cleared)
|
||||
queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
|
||||
return !cleared
|
||||
/mob/living/silicon/robot/proc/alarm_cleared(datum/source, alarm_type, area/source_area)
|
||||
SIGNAL_HANDLER
|
||||
queueAlarm("--- [alarm_type] alarm in [source_area.name] has been cleared.", alarm_type, FALSE)
|
||||
|
||||
/mob/living/silicon/robot/can_interact_with(atom/A)
|
||||
if (A == modularInterface)
|
||||
|
||||
@@ -114,14 +114,6 @@
|
||||
///Ionpulse effect.
|
||||
var/datum/effect_system/trail_follow/ion/ion_trail
|
||||
|
||||
var/alarms = list(
|
||||
"Motion" = list(),
|
||||
"Fire" = list(),
|
||||
"Atmosphere" = list(),
|
||||
"Power" = list(),
|
||||
"Camera" = list(),
|
||||
"Burglar" = list())
|
||||
|
||||
// ------------------------------------------ Misc
|
||||
var/toner = 0
|
||||
var/tonermax = 40
|
||||
@@ -139,6 +131,8 @@
|
||||
|
||||
/// the last health before updating - to check net change in health
|
||||
var/previous_health
|
||||
///Alarm listener datum, handes caring about alarm events and such
|
||||
var/datum/alarm_listener/listener
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
var/obj/item/radio/borg/radio = null ///If this is a path, this gets created as an object in Initialize.
|
||||
|
||||
var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
|
||||
var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
|
||||
var/list/alarm_types_show = list(ALARM_ATMOS = 0, ALARM_FIRE = 0, ALARM_POWER = 0, ALARM_CAMERA = 0, ALARM_MOTION = 0)
|
||||
var/list/alarm_types_clear = list(ALARM_ATMOS = 0, ALARM_FIRE = 0, ALARM_POWER = 0, ALARM_CAMERA = 0, ALARM_MOTION = 0)
|
||||
|
||||
var/lawcheck[1]
|
||||
var/ioncheck[1]
|
||||
@@ -79,16 +79,7 @@
|
||||
/mob/living/silicon/contents_explosion(severity, target)
|
||||
return
|
||||
|
||||
/mob/living/silicon/proc/cancelAlarm()
|
||||
return
|
||||
|
||||
/mob/living/silicon/proc/freeCamera()
|
||||
return
|
||||
|
||||
/mob/living/silicon/proc/triggerAlarm()
|
||||
return
|
||||
|
||||
/mob/living/silicon/proc/queueAlarm(message, type, incoming = 1)
|
||||
/mob/living/silicon/proc/queueAlarm(message, type, incoming = FALSE)
|
||||
var/in_cooldown = (alarms_to_show.len > 0 || alarms_to_clear.len > 0)
|
||||
if(incoming)
|
||||
alarms_to_show += message
|
||||
@@ -109,24 +100,8 @@
|
||||
else if(alarms_to_show.len)
|
||||
|
||||
var/msg = "--- "
|
||||
|
||||
if(alarm_types_show["Burglar"])
|
||||
msg += "BURGLAR: [alarm_types_show["Burglar"]] alarms detected. - "
|
||||
|
||||
if(alarm_types_show["Motion"])
|
||||
msg += "MOTION: [alarm_types_show["Motion"]] alarms detected. - "
|
||||
|
||||
if(alarm_types_show["Fire"])
|
||||
msg += "FIRE: [alarm_types_show["Fire"]] alarms detected. - "
|
||||
|
||||
if(alarm_types_show["Atmosphere"])
|
||||
msg += "ATMOSPHERE: [alarm_types_show["Atmosphere"]] alarms detected. - "
|
||||
|
||||
if(alarm_types_show["Power"])
|
||||
msg += "POWER: [alarm_types_show["Power"]] alarms detected. - "
|
||||
|
||||
if(alarm_types_show["Camera"])
|
||||
msg += "CAMERA: [alarm_types_show["Camera"]] alarms detected. - "
|
||||
for(var/alarm_type in alarm_types_show)
|
||||
msg += "[uppertext(alarm_type)]: [alarm_types_show[alarm_type]] alarms detected. - "
|
||||
|
||||
msg += "<A href=?src=[REF(src)];showalerts=1'>\[Show Alerts\]</a>"
|
||||
to_chat(src, msg)
|
||||
@@ -138,20 +113,8 @@
|
||||
else if(alarms_to_clear.len)
|
||||
var/msg = "--- "
|
||||
|
||||
if(alarm_types_clear["Motion"])
|
||||
msg += "MOTION: [alarm_types_clear["Motion"]] alarms cleared. - "
|
||||
|
||||
if(alarm_types_clear["Fire"])
|
||||
msg += "FIRE: [alarm_types_clear["Fire"]] alarms cleared. - "
|
||||
|
||||
if(alarm_types_clear["Atmosphere"])
|
||||
msg += "ATMOSPHERE: [alarm_types_clear["Atmosphere"]] alarms cleared. - "
|
||||
|
||||
if(alarm_types_clear["Power"])
|
||||
msg += "POWER: [alarm_types_clear["Power"]] alarms cleared. - "
|
||||
|
||||
if(alarm_types_show["Camera"])
|
||||
msg += "CAMERA: [alarm_types_clear["Camera"]] alarms cleared. - "
|
||||
for(var/alarm_type in alarm_types_clear)
|
||||
msg += "[uppertext(alarm_type)]: [alarm_types_clear[alarm_type]] alarms cleared. - "
|
||||
|
||||
msg += "<A href=?src=[REF(src)];showalerts=1'>\[Show Alerts\]</a>"
|
||||
to_chat(src, msg)
|
||||
|
||||
@@ -63,8 +63,8 @@
|
||||
"3. Your goals are to actively build, maintain, repair, improve, and provide power to the best of your abilities within the facility that housed your activation." //for derelict drones so they don't go to station.
|
||||
/// Amount of damage sustained if hit by a heavy EMP pulse
|
||||
var/heavy_emp_damage = 25
|
||||
/// List of active alarms. See [/mob/living/simple_animal/drone/proc/triggerAlarm] and [/mob/living/simple_animal/drone/proc/cancelAlarm]
|
||||
var/alarms = list("Atmosphere" = list(), "Fire" = list(), "Power" = list())
|
||||
///Alarm listener datum, handes caring about alarm events and such
|
||||
var/datum/alarm_listener/listener
|
||||
/// Internal storage slot. Fits any item
|
||||
var/obj/item/internal_storage
|
||||
/// Headwear slot
|
||||
@@ -181,6 +181,12 @@
|
||||
|
||||
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
|
||||
|
||||
listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER), list(z))
|
||||
RegisterSignal(listener, COMSIG_ALARM_TRIGGERED, .proc/alarm_triggered)
|
||||
RegisterSignal(listener, COMSIG_ALARM_CLEARED, .proc/alarm_cleared)
|
||||
listener.RegisterSignal(src, COMSIG_LIVING_DEATH, /datum/alarm_listener/proc/prevent_alarm_changes)
|
||||
listener.RegisterSignal(src, COMSIG_LIVING_REVIVE, /datum/alarm_listener/proc/allow_alarm_changes)
|
||||
|
||||
/mob/living/simple_animal/drone/med_hud_set_health()
|
||||
var/image/holder = hud_list[DIAG_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
@@ -200,7 +206,8 @@
|
||||
|
||||
/mob/living/simple_animal/drone/Destroy()
|
||||
GLOB.drones_list -= src
|
||||
qdel(access_card) //Otherwise it ends up on the floor!
|
||||
QDEL_NULL(access_card) //Otherwise it ends up on the floor!
|
||||
QDEL_NULL(listener)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/drone/Login()
|
||||
@@ -289,60 +296,13 @@
|
||||
adjustBruteLoss(heavy_emp_damage)
|
||||
to_chat(src, span_userdanger("HeAV% DA%^MMA+G TO I/O CIR!%UUT!"))
|
||||
|
||||
/mob/living/simple_animal/drone/proc/alarm_triggered(datum/source, alarm_type, area/source_area)
|
||||
SIGNAL_HANDLER
|
||||
to_chat(src, "--- [alarm_type] alarm detected in [source_area.name]!")
|
||||
|
||||
/**
|
||||
* Alerts drones about different priorities of alarms
|
||||
*
|
||||
* Arguments:
|
||||
* * class - One of the keys listed in [/mob/living/simple_animal/drone/var/alarms]
|
||||
* * A - [/area] the alarm occurs
|
||||
* * O - unused argument, see [/mob/living/silicon/robot/triggerAlarm]
|
||||
* * alarmsource - [/atom] source of the alarm
|
||||
*/
|
||||
/mob/living/simple_animal/drone/proc/triggerAlarm(class, area/home, cameras, obj/source)
|
||||
if(source.z != z)
|
||||
return
|
||||
if(stat == DEAD)
|
||||
return
|
||||
var/list/our_sort = alarms[class]
|
||||
for(var/areaname in our_sort)
|
||||
if (areaname == home.name)
|
||||
var/list/alarm = our_sort[areaname]
|
||||
var/list/sources = alarm[2]
|
||||
if (!(source in sources))
|
||||
sources += source
|
||||
return TRUE
|
||||
|
||||
our_sort[home.name] = list(home, list(source))
|
||||
to_chat(src, "--- [class] alarm detected in [home.name]!")
|
||||
|
||||
///This isn't currently needed since drones do jack shit with cameras. I hate this code so much
|
||||
/mob/living/simple_animal/drone/proc/freeCamera(area/home, obj/machinery/camera/cam)
|
||||
return
|
||||
|
||||
/**
|
||||
* Clears alarm and alerts drones
|
||||
*
|
||||
* Arguments:
|
||||
* * class - One of the keys listed in [/mob/living/simple_animal/drone/var/alarms]
|
||||
* * A - [/area] the alarm occurs
|
||||
* * alarmsource - [/atom] source of the alarm
|
||||
*/
|
||||
/mob/living/simple_animal/drone/proc/cancelAlarm(class, area/A, obj/origin)
|
||||
if(stat != DEAD)
|
||||
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[2]
|
||||
if (origin in srcs)
|
||||
srcs -= origin
|
||||
if (srcs.len == 0)
|
||||
cleared = 1
|
||||
L -= I
|
||||
if(cleared)
|
||||
to_chat(src, "--- [class] alarm in [A.name] has been cleared.")
|
||||
/mob/living/simple_animal/drone/proc/alarm_cleared(datum/source, alarm_type, area/source_area)
|
||||
SIGNAL_HANDLER
|
||||
to_chat(src, "--- [alarm_type] alarm in [source_area.name] has been cleared.")
|
||||
|
||||
/mob/living/simple_animal/drone/proc/blacklist_on_try_use_machine(datum/source, obj/machinery/machine)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
@@ -10,7 +10,20 @@
|
||||
tgui_id = "NtosStationAlertConsole"
|
||||
program_icon = "bell"
|
||||
var/has_alert = 0
|
||||
var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
|
||||
///Listens for alarms, manages our listing of alarms
|
||||
var/datum/alarm_listener/listener
|
||||
|
||||
/datum/computer_file/program/alarm_monitor/New()
|
||||
//We want to send an alarm if we're in one of the mining home areas
|
||||
//Or if we're on station. Otherwise, die.
|
||||
var/list/allowed_areas = GLOB.the_station_areas + typesof(/area/mine)
|
||||
listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER), null, allowed_areas)
|
||||
RegisterSignal(listener, list(COMSIG_ALARM_TRIGGERED, COMSIG_ALARM_CLEARED), .proc/update_alarm_display)
|
||||
return ..()
|
||||
|
||||
/datum/computer_file/program/alarm_monitor/Destroy()
|
||||
QDEL_NULL(listener)
|
||||
return ..()
|
||||
|
||||
/datum/computer_file/program/alarm_monitor/process_tick()
|
||||
..()
|
||||
@@ -30,87 +43,19 @@
|
||||
var/list/data = get_header_data()
|
||||
|
||||
data["alarms"] = list()
|
||||
for(var/class in alarms)
|
||||
data["alarms"][class] = list()
|
||||
for(var/area in alarms[class])
|
||||
data["alarms"][class] += area
|
||||
var/list/alarms = listener.alarms
|
||||
for(var/alarm_type in alarms)
|
||||
data["alarms"][alarm_type] = list()
|
||||
for(var/area in alarms[alarm_type])
|
||||
data["alarms"][alarm_type] += area
|
||||
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/alarm_monitor/proc/triggerAlarm(class, area/home, cameras, obj/source)
|
||||
if(is_station_level(source.z))
|
||||
if(!(home.type in GLOB.the_station_areas))
|
||||
return
|
||||
else if(!is_mining_level(source.z) || istype(home, /area/ruin))
|
||||
return
|
||||
|
||||
var/list/our_sort = alarms[class]
|
||||
for(var/areaname in our_sort)
|
||||
if (areaname == home.name)
|
||||
var/list/alarm = our_sort[areaname]
|
||||
var/list/sources = alarm[3]
|
||||
if (!(source in sources))
|
||||
sources += source
|
||||
return TRUE
|
||||
|
||||
var/obj/machinery/camera/cam = null
|
||||
var/list/our_cams = null
|
||||
if(cameras && islist(cameras))
|
||||
our_cams = cameras
|
||||
if (our_cams.len == 1)
|
||||
cam = our_cams[1]
|
||||
else if(cameras && istype(cameras, /obj/machinery/camera))
|
||||
cam = cameras
|
||||
our_sort[home.name] = list(home, (cam ? cam : cameras), list(source))
|
||||
|
||||
update_alarm_display()
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/alarm_monitor/proc/freeCamera(area/home, obj/machinery/camera/cam)
|
||||
for(var/class in alarms)
|
||||
var/our_area = alarms[class][home.name]
|
||||
if(!our_area)
|
||||
continue
|
||||
var/cams = our_area[2] //Get the cameras
|
||||
if(!cams)
|
||||
continue
|
||||
if(islist(cams))
|
||||
cams -= cam
|
||||
if(length(cams) == 1)
|
||||
our_area[2] = cams[1]
|
||||
else
|
||||
our_area[2] = null
|
||||
|
||||
/datum/computer_file/program/alarm_monitor/proc/cancelAlarm(class, area/A, obj/origin)
|
||||
var/list/L = alarms[class]
|
||||
var/cleared = 0
|
||||
var/arealevelalarm = FALSE // set to TRUE for alarms that set/clear whole areas
|
||||
if (class=="Fire")
|
||||
arealevelalarm = TRUE
|
||||
for (var/I in L)
|
||||
if (I == A.name)
|
||||
if (!arealevelalarm) // the traditional behaviour
|
||||
var/list/alarm = L[I]
|
||||
var/list/srcs = alarm[3]
|
||||
if (origin in srcs)
|
||||
srcs -= origin
|
||||
if (srcs.len == 0)
|
||||
cleared = 1
|
||||
L -= I
|
||||
else
|
||||
L -= I // wipe the instances entirely
|
||||
cleared = 1
|
||||
|
||||
|
||||
update_alarm_display()
|
||||
return !cleared
|
||||
|
||||
/datum/computer_file/program/alarm_monitor/proc/update_alarm_display()
|
||||
SIGNAL_HANDLER
|
||||
has_alert = FALSE
|
||||
for(var/cat in alarms)
|
||||
var/list/L = alarms[cat]
|
||||
if(L.len)
|
||||
has_alert = TRUE
|
||||
if(length(listener.alarms))
|
||||
has_alert = TRUE
|
||||
|
||||
/datum/computer_file/program/alarm_monitor/run_program(mob/user)
|
||||
. = ..(user)
|
||||
@@ -118,4 +63,4 @@
|
||||
|
||||
/datum/computer_file/program/alarm_monitor/kill_program(forced = FALSE)
|
||||
GLOB.alarmdisplay -= src
|
||||
..()
|
||||
return ..()
|
||||
|
||||
@@ -160,6 +160,8 @@
|
||||
var/update_overlay = -1
|
||||
var/icon_update_needed = FALSE
|
||||
var/obj/machinery/computer/apc_control/remote_control = null
|
||||
///Represents a signel source of power alarms for this apc
|
||||
var/datum/alarm_handler/alarm_manager
|
||||
|
||||
/obj/machinery/power/apc/unlocked
|
||||
locked = FALSE
|
||||
@@ -258,7 +260,7 @@
|
||||
area.power_equip = FALSE
|
||||
area.power_environ = FALSE
|
||||
area.power_change()
|
||||
area.poweralert(FALSE, src)
|
||||
QDEL_NULL(alarm_manager)
|
||||
if(occupier)
|
||||
malfvacate(1)
|
||||
qdel(wires)
|
||||
@@ -285,6 +287,7 @@
|
||||
/obj/machinery/power/apc/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/atmos_sensitive, mapload)
|
||||
alarm_manager = new(src)
|
||||
|
||||
if(!mapload)
|
||||
return
|
||||
@@ -1309,24 +1312,24 @@
|
||||
equipment = autoset(equipment, AUTOSET_FORCE_OFF)
|
||||
lighting = autoset(lighting, AUTOSET_FORCE_OFF)
|
||||
environ = autoset(environ, AUTOSET_FORCE_OFF)
|
||||
area.poweralert(TRUE, src)
|
||||
alarm_manager.send_alarm(ALARM_POWER)
|
||||
else if(cell.percent() < 15 && longtermpower < 0) // <15%, turn off lighting & equipment
|
||||
equipment = autoset(equipment, AUTOSET_OFF)
|
||||
lighting = autoset(lighting, AUTOSET_OFF)
|
||||
environ = autoset(environ, AUTOSET_ON)
|
||||
area.poweralert(TRUE, src)
|
||||
alarm_manager.send_alarm(ALARM_POWER)
|
||||
else if(cell.percent() < 30 && longtermpower < 0) // <30%, turn off equipment
|
||||
equipment = autoset(equipment, AUTOSET_OFF)
|
||||
lighting = autoset(lighting, AUTOSET_ON)
|
||||
environ = autoset(environ, AUTOSET_ON)
|
||||
area.poweralert(TRUE, src)
|
||||
alarm_manager.send_alarm(ALARM_POWER)
|
||||
else // otherwise all can be on
|
||||
equipment = autoset(equipment, AUTOSET_ON)
|
||||
lighting = autoset(lighting, AUTOSET_ON)
|
||||
environ = autoset(environ, AUTOSET_ON)
|
||||
area.poweralert(FALSE, src)
|
||||
if(cell.percent() > 75)
|
||||
area.poweralert(FALSE, src)
|
||||
alarm_manager.clear_alarm(ALARM_POWER)
|
||||
|
||||
|
||||
// now trickle-charge the cell
|
||||
if(chargemode && charging == APC_CHARGING && operating)
|
||||
@@ -1368,7 +1371,7 @@
|
||||
equipment = autoset(equipment, AUTOSET_FORCE_OFF)
|
||||
lighting = autoset(lighting, AUTOSET_FORCE_OFF)
|
||||
environ = autoset(environ, AUTOSET_FORCE_OFF)
|
||||
area.poweralert(TRUE, src)
|
||||
alarm_manager.send_alarm(ALARM_POWER)
|
||||
|
||||
// update icon & area power if anything changed
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "code\__DEFINES\admin.dm"
|
||||
#include "code\__DEFINES\adventure.dm"
|
||||
#include "code\__DEFINES\ai.dm"
|
||||
#include "code\__DEFINES\alarm.dm"
|
||||
#include "code\__DEFINES\antagonists.dm"
|
||||
#include "code\__DEFINES\aquarium.dm"
|
||||
#include "code\__DEFINES\art.dm"
|
||||
@@ -397,6 +398,7 @@
|
||||
#include "code\controllers\subsystem\processing\wet_floors.dm"
|
||||
#include "code\datums\action.dm"
|
||||
#include "code\datums\ai_laws.dm"
|
||||
#include "code\datums\alarm.dm"
|
||||
#include "code\datums\armor.dm"
|
||||
#include "code\datums\beam.dm"
|
||||
#include "code\datums\browser.dm"
|
||||
|
||||
Reference in New Issue
Block a user