Files
Bubberstation/code/datums/alarm.dm
Marina fcaa0b24db Alphabetized, fixed spelling error, clarifying event descriptions. Polish (#69707)
About The Pull Request

Alphabetized several long lists of strings so its easier for us to look through them, just code polish, nothing the players would see.

Fixed some minor spelling errors as well.

Clarified door bolt state to be less ambiguous in the door wiring gui.
Originally it would say the door bolts have fallen, and the door bolts "Look up". i dont know about you but that was very not clear for me to read. Like where are the bolts? In the door or the frame? Arnt there bolts on top and bottom? Just didn't make sense to me.

Now it says "Have engaged!" & "Have disengaged"
hopefully that makes the state clearer at a glance.

I also added a small handful of funny texts to some string files. See changelog
Why It's Good For The Game

Well, who doesn't like a bit of polish? Just makes the game a little easier for people.
Also funny text funny text.
Changelog

spelling: improves spelling and adds more flavortext
2022-09-11 21:51:01 +12:00

210 lines
8.1 KiB
Plaintext

//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 separate listing for each reviever
//You only receive alarms sent after you start to listen
//Also of note, due to an optimization done on areas, one alarm handler will only ever send one "on" or "off" alarm
//So the whole only receiving 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 = (isdatum(source_atom)) ? 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_SIGNAL(src, COMSIG_ALARM_TRIGGERED, alarm_type, our_area)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_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_SIGNAL(src, COMSIG_ALARM_CLEARED, alarm_type, our_area)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_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_GLOB_ALARM_FIRE(alarm_type), .proc/add_alarm)
RegisterSignal(SSdcs, COMSIG_GLOB_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)
SIGNAL_HANDLER
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_LISTENER_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)
SIGNAL_HANDLER
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
if(!length(alarms_of_our_type))
alarms -= alarm_type
SEND_SIGNAL(src, COMSIG_ALARM_LISTENER_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