Basic main structure for centralized alarm handling.

This commit is contained in:
PsiOmega
2015-02-17 08:34:26 +01:00
parent 3ddd0b480f
commit 2e9c266a2f
23 changed files with 345 additions and 246 deletions
+78
View File
@@ -0,0 +1,78 @@
/datum/alarm_source
var/source = null // The source trigger
var/source_name = "" // The name of the source should it be lost (for example a destroyed camera)
var/duration = 0 // How long this source will be alarming, 0 for indefinetely.
var/start_time = 0 // When this source began alarming.
var/end_time = 0 // Use to set when this trigger should clear, in case the source is lost.
/datum/alarm_source/New(var/atom/source)
src.source = source
source_name = source.name
start_time = world.time
/datum/alarm
var/atom/origin //Used to identify the alarm area.
var/list/sources = new() //List of sources triggering the alarm. Used to determine when the alarm should be cleared.
var/list/sources_assoc = new() //Associative list of source triggers. Used to efficiently acquire the alarm source.
var/list/cameras //List of cameras that can be switched to, if the player has that capability.
var/area/last_area //The last acquired area, used should origin be lost (for example a destroyed borg containing an alarming camera).
/datum/alarm/New(var/atom/origin, var/atom/source, var/duration)
src.origin = origin
last_area = alarm_area()
set_duration(source, duration)
/datum/alarm/proc/set_duration(var/atom/source, var/duration)
var/datum/alarm_source/AS = sources[source]
if(!AS)
AS = new/datum/alarm_source(source)
sources += AS
sources_assoc[source] = AS
// Currently only non-0 durations can be altered (normal alarms VS EMP blasts)
if(AS.duration)
AS.duration = duration
/datum/alarm/proc/clear(var/source)
var/datum/alarm_source/AS = sources[source]
sources -= AS
sources_assoc -= source
/datum/alarm/proc/alarm_area()
if(!origin)
return last_area
last_area = origin.get_alarm_area()
return last_area
/datum/alarm/proc/cameras()
if(!origin)
return list()
if(!cameras)
cameras = origin.get_alarm_cameras()
return cameras
/atom/proc/get_alarm_area()
return get_area(src)
/area/get_alarm_area()
return src
/atom/proc/get_alarm_cameras()
var/area/A = get_area(src)
return A.get_cameras()
/area/get_alarm_cameras()
return get_cameras()
/mob/living/silicon/robot/get_alarm_cameras()
var/list/cameras = ..()
if(camera)
cameras += camera
return cameras
/mob/living/silicon/robot/syndicate/get_alarm_cameras()
return list()
+112
View File
@@ -0,0 +1,112 @@
#define ALARM_ORIGIN_LOST "Origin Lost"
/datum/alarm_handler
var/category = ""
var/list/datum/alarm/alarms = new // All alarms, to handle cases when origin has been deleted with one or more active alarms
var/list/datum/alarm/alarms_assoc = new // Associative list of alarms, to efficiently acquire them based on origin.
/datum/alarm_handler/proc/process()
/*
for(var/datum/alarm/A in alarms)
var/datum/alarm_source/AS = A.source
// Alarm owner has been deleted. Clean up in at most 15 seconds
if(!AS.owner && !AS.end_time)
AS.end_time = world.time + SecondsToTicks(15)
if(AS.duration || AS.end_time)
if(world.time > (AS.start_time + AS.duration) || world.time > AS.end_time)
//Somethingthing..
*/
/datum/alarm_handler/proc/triggerAlarm(var/atom/origin, var/atom/source, var/duration = 0)
//Proper origin and source mandatory
if(!origin || !source)
return
//see if there is already an alarm of this origin
var/alarm_key = origin.get_alarm_key()
var/datum/alarm/existing = alarms_assoc[alarm_key]
if(existing)
existing.set_duration(source, duration)
else
existing = new/datum/alarm(origin, source, duration)
alarms |= existing
alarms_assoc[alarm_key] = existing
/datum/alarm_handler/proc/cancelAlarm(var/atom/origin, var/source)
//Proper origin and source mandatory
if(!origin || !source)
return
var/alarm_key = origin.get_alarm_key()
var/datum/alarm/existing = alarms_assoc[alarm_key]
if(existing)
existing.clear(source)
if (!existing.sources.len)
alarms -= existing
alarms_assoc -= alarm_key
/atom/proc/get_alarm_key()
return src
/turf/get_alarm_key()
return get_area(src)
/obj/item/device/alarm_debug
name = "An alarm debug tool - Self"
desc = "Alarm Up. Alarm Reset."
icon = 'icons/obj/radio.dmi'
icon_state = "beacon"
item_state = "signaler"
/obj/item/device/alarm_debug/loc
name = "An alarm debug tool - Loc"
/obj/item/device/alarm_debug/verb/alarm()
set name = "Alarm"
set category = "Debug"
usr << "Raising alarm"
camera_alarm.triggerAlarm(src, src)
/obj/item/device/alarm_debug/verb/reset()
set name = "Reset"
set category = "Debug"
usr << "Raising alarm"
camera_alarm.triggerAlarm(src, src)
/obj/item/device/alarm_debug/verb/tell_me()
set name = "Tell"
set category = "Debug"
usr << "Telling about alarms"
var/list/datum/alarm/alarms = camera_alarm.alarms
var/list/datum/alarm/alarms_assoc = camera_alarm.alarms_assoc
world << "List"
for(var/datum/alarm/A in alarms)
world << "Origin: [A.origin ? A.origin : ALARM_ORIGIN_LOST]"
world << "Alarm area: [A.alarm_area()]"
for(var/source in A.sources)
world << "Source: [source]"
world << "Assoc"
for(var/atom/origin in alarms_assoc)
world << "Origin: [origin ? origin : ALARM_ORIGIN_LOST]"
var/datum/alarm/A = alarms_assoc[origin]
world << "Alarm area: [A.alarm_area()]"
for(var/source in A.sources)
world << "Source: [source]"
/obj/item/device/alarm_debug/loc/alarm()
set name = "Alarm"
set category = "Debug"
usr << "Raising alarm"
camera_alarm.triggerAlarm(src.loc, src)
/obj/item/device/alarm_debug/loc/reset()
set name = "Reset"
set category = "Debug"
usr << "Clearing alarm"
camera_alarm.cancelAlarm(src.loc, src)
+2
View File
@@ -0,0 +1,2 @@
/datum/alarm_handler/atmosphere
category = "Atmosphere"
+2
View File
@@ -0,0 +1,2 @@
/datum/alarm_handler/camera
category = "Camera"
+2
View File
@@ -0,0 +1,2 @@
/datum/alarm_handler/fire_alarm
category = "Fire"
+2
View File
@@ -0,0 +1,2 @@
/datum/alarm_handler/motion
category = "Motion"
+2
View File
@@ -0,0 +1,2 @@
/datum/alarm_handler/power
category = "Power"
+2 -48
View File
@@ -324,31 +324,8 @@ var/list/ai_verbs_default = list(
set category = "AI Commands"
set name = "Show 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/alarmlist = alarms[cat]
if (alarmlist.len)
for (var/area_name in alarmlist)
var/datum/alarm/alarm = alarmlist[area_name]
dat += "<NOBR>"
var/cameratext = ""
if (alarm.cameras)
for (var/obj/machinery/camera/I in alarm.cameras)
cameratext += text("[]<A HREF=?src=\ref[];switchcamera=\ref[]>[]</A>", (cameratext=="") ? "" : " | ", src, I, I.c_tag)
dat += text("-- [] ([])", alarm.area.name, (cameratext)? cameratext : "No Camera")
if (alarm.sources.len > 1)
dat += text(" - [] sources", alarm.sources.len)
dat += "</NOBR><BR>\n"
else
dat += "-- All Systems Nominal<BR>\n"
dat += "<BR>\n"
viewalerts = 1
src << browse(dat, "window=aialerts&can_close=0")
//PsiFix
//nano_alarm.ui_interact(usr)
// this verb lets the ai see the stations manifest
/mob/living/silicon/ai/proc/ai_roster()
@@ -521,29 +498,6 @@ var/list/ai_verbs_default = list(
return 1
/mob/living/silicon/ai/triggerAlarm(var/class, area/A, list/cameralist, var/source)
if (stat == 2)
return 1
..()
var/cameratext = ""
for (var/obj/machinery/camera/C in cameralist)
cameratext += "[(cameratext == "")? "" : "|"]<A HREF=?src=\ref[src];switchcamera=\ref[C]>[C.c_tag]</A>"
queueAlarm("--- [class] alarm detected in [A.name]! ([(cameratext)? cameratext : "No Camera"])", class)
if (viewalerts) ai_alerts()
/mob/living/silicon/ai/cancelAlarm(var/class, area/A as area, var/source)
var/has_alarm = ..()
if (!has_alarm)
queueAlarm(text("--- [] alarm in [] has been cleared.", class, A.name), class, 0)
if (viewalerts) ai_alerts()
return has_alarm
/mob/living/silicon/ai/cancel_camera()
set category = "AI Commands"
set name = "Cancel Camera View"
-111
View File
@@ -1,111 +0,0 @@
/datum/alarm
var/area/area //the area associated with the alarm. Used to identify the alarm
var/list/sources //list of things triggering the alarm. Used to determine when the alarm should be cleared.
var/list/cameras //list of cameras that can be switched to, if the player has that capability.
/datum/alarm/New(area/A, list/sourcelist=list(), list/cameralist=list())
area = A
sources = sourcelist
cameras = cameralist
/mob/living/silicon
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list()) //each sublist stores alarms keyed by the area name
var/list/alarms_to_show = list()
var/list/alarms_to_clear = list()
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)
/mob/living/silicon/proc/triggerAlarm(var/class, area/A, list/cameralist, var/source)
var/list/alarmlist = alarms[class]
//see if there is already an alarm of this class for this area
if (A.name in alarmlist)
var/datum/alarm/existing = alarmlist[A.name]
existing.sources += source
existing.cameras |= cameralist
else
alarmlist[A.name] = new /datum/alarm(A, list(source), cameralist)
/mob/living/silicon/proc/cancelAlarm(var/class, area/A as area, var/source)
var/cleared = 0
var/list/alarmlist = alarms[class]
if (A.name in alarmlist)
var/datum/alarm/alarm = alarmlist[A.name]
alarm.sources -= source
if (!(alarm.sources.len))
cleared = 1
alarmlist -= A.name
return !cleared
/mob/living/silicon/proc/queueAlarm(var/message, var/type, var/incoming = 1)
var/in_cooldown = (alarms_to_show.len > 0 || alarms_to_clear.len > 0)
if(incoming)
alarms_to_show += message
alarm_types_show[type] += 1
else
alarms_to_clear += message
alarm_types_clear[type] += 1
if(!in_cooldown)
spawn(10 * 10) // 10 seconds
if(alarms_to_show.len < 5)
for(var/msg in alarms_to_show)
src << msg
else if(alarms_to_show.len)
var/msg = "--- "
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["Power"]] alarms detected. - "
msg += "<A href=?src=\ref[src];showalerts=1'>\[Show Alerts\]</a>"
src << msg
if(alarms_to_clear.len < 3)
for(var/msg in alarms_to_clear)
src << msg
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_show["Power"]] alarms detected. - "
msg += "<A href=?src=\ref[src];showalerts=1'>\[Show Alerts\]</a>"
src << msg
alarms_to_show = list()
alarms_to_clear = list()
for(var/i = 1; i < alarm_types_show.len; i++)
alarm_types_show[i] = 0
for(var/i = 1; i < alarm_types_clear.len; i++)
alarm_types_clear[i] = 0
+2 -38
View File
@@ -450,25 +450,8 @@ var/list/robot_verbs_default = list(
/mob/living/silicon/robot/proc/robot_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=robotalerts'>Close</A><BR><BR>"
for (var/cat in alarms)
dat += text("<B>[cat]</B><BR>\n")
var/list/alarmlist = alarms[cat]
if (alarmlist.len)
for (var/area_name in alarmlist)
var/datum/alarm/alarm = alarmlist[area_name]
dat += "<NOBR>"
dat += text("-- [area_name]")
if (alarm.sources.len > 1)
dat += text("- [alarm.sources.len] sources")
dat += "</NOBR><BR>\n"
else
dat += "-- All Systems Nominal<BR>\n"
dat += "<BR>\n"
viewalerts = 1
src << browse(dat, "window=robotalerts&can_close=0")
//PsiFix
//nano_alarm.ui_interact(usr)
/mob/living/silicon/robot/proc/self_diagnosis()
if(!is_component_functioning("diagnosis unit"))
@@ -636,25 +619,6 @@ var/list/robot_verbs_default = list(
return
return
/mob/living/silicon/robot/triggerAlarm(var/class, area/A, list/cameralist, var/source)
if (stat == 2)
return 1
..()
queueAlarm(text("--- [class] alarm detected in [A.name]!"), class)
/mob/living/silicon/robot/cancelAlarm(var/class, area/A as area, obj/origin)
var/has_alarm = ..()
if (!has_alarm)
queueAlarm(text("--- [class] alarm in [A.name] has been cleared."), class, 0)
// if (viewalerts) robot_alerts()
return has_alarm
/mob/living/silicon/robot/attackby(obj/item/weapon/W as obj, mob/user as mob)
if (istype(W, /obj/item/weapon/handcuffs)) // fuck i don't even know why isrobot() in handcuff code isn't working so this will have to do
return
@@ -23,6 +23,7 @@
var/local_transmit //If set, can only speak to others of the same type within a short range.
var/sensor_mode = 0 //Determines the current HUD.
#define SEC_HUD 1 //Security HUD mode
#define MED_HUD 2 //Medical HUD mode
+3 -1
View File
@@ -808,6 +808,8 @@ note dizziness decrements automatically in the mob's Life() proc.
stat(null,"Obj-[master_controller.objects_cost]\t#[processing_objects.len]")
stat(null,"Net-[master_controller.networks_cost]\tPnet-[master_controller.powernets_cost]")
stat(null,"NanoUI-[master_controller.nano_cost]\t#[nanomanager.processing_uis.len]")
stat(null,"Event-[master_controller.events_cost]\t# [event_manager.active_events.len]")
alarm_manager.stat_entry()
stat(null,"Tick-[master_controller.ticker_cost]\tALL-[master_controller.total_cost]")
else
stat(null,"MasterController-ERROR")
@@ -1210,4 +1212,4 @@ mob/proc/yank_out_object()
/mob/verb/westfaceperm()
set hidden = 1
facing_dir = null
set_face_dir(WEST)
set_face_dir(WEST)