From 2e9c266a2f47a7f34ef4487354a2bc5de29e085f Mon Sep 17 00:00:00 2001 From: PsiOmega Date: Mon, 9 Feb 2015 08:22:47 +0100 Subject: [PATCH] Basic main structure for centralized alarm handling. --- baystation12.dme | 10 +- code/__HELPERS/game.dm | 7 +- code/controllers/master_controller.dm | 14 ++- code/controllers/subsystem/alarms.dm | 27 +++++ code/controllers/subsystems.dm | 46 +++++++ code/controllers/verbs.dm | 5 +- code/game/area/areas.dm | 27 ++--- code/game/machinery/camera/camera.dm | 36 +++--- code/game/machinery/camera/motion.dm | 6 +- code/game/machinery/computer/camera.dm | 2 + code/global.dm | 5 +- code/modules/alarm/alarm.dm | 78 ++++++++++++ code/modules/alarm/alarm_handler.dm | 112 ++++++++++++++++++ code/modules/alarm/atmosphere_alarm.dm | 2 + code/modules/alarm/camera_alarm.dm | 2 + code/modules/alarm/fire_alarm.dm | 2 + code/modules/alarm/motion_alarm.dm | 2 + code/modules/alarm/power_alarm.dm | 2 + code/modules/mob/living/silicon/ai/ai.dm | 50 +------- code/modules/mob/living/silicon/alarm.dm | 111 ----------------- .../modules/mob/living/silicon/robot/robot.dm | 40 +------ code/modules/mob/living/silicon/silicon.dm | 1 + code/modules/mob/mob.dm | 4 +- 23 files changed, 345 insertions(+), 246 deletions(-) create mode 100644 code/controllers/subsystem/alarms.dm create mode 100644 code/controllers/subsystems.dm create mode 100644 code/modules/alarm/alarm.dm create mode 100644 code/modules/alarm/alarm_handler.dm create mode 100644 code/modules/alarm/atmosphere_alarm.dm create mode 100644 code/modules/alarm/camera_alarm.dm create mode 100644 code/modules/alarm/fire_alarm.dm create mode 100644 code/modules/alarm/motion_alarm.dm create mode 100644 code/modules/alarm/power_alarm.dm delete mode 100644 code/modules/mob/living/silicon/alarm.dm diff --git a/baystation12.dme b/baystation12.dme index 82506f8bed..89b3383968 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -93,8 +93,10 @@ #include "code\controllers\lighting_controller.dm" #include "code\controllers\master_controller.dm" #include "code\controllers\shuttle_controller.dm" +#include "code\controllers\subsystems.dm" #include "code\controllers\verbs.dm" #include "code\controllers\voting.dm" +#include "code\controllers\subsystem\alarms.dm" #include "code\datums\ai_laws.dm" #include "code\datums\browser.dm" #include "code\datums\computerfiles.dm" @@ -806,6 +808,13 @@ #include "code\modules\admin\verbs\ticklag.dm" #include "code\modules\admin\verbs\tripAI.dm" #include "code\modules\admin\verbs\vox_raiders.dm" +#include "code\modules\alarm\alarm.dm" +#include "code\modules\alarm\alarm_handler.dm" +#include "code\modules\alarm\atmosphere_alarm.dm" +#include "code\modules\alarm\camera_alarm.dm" +#include "code\modules\alarm\fire_alarm.dm" +#include "code\modules\alarm\motion_alarm.dm" +#include "code\modules\alarm\power_alarm.dm" #include "code\modules\assembly\assembly.dm" #include "code\modules\assembly\bomb.dm" #include "code\modules\assembly\helpers.dm" @@ -1115,7 +1124,6 @@ #include "code\modules\mob\living\carbon\monkey\login.dm" #include "code\modules\mob\living\carbon\monkey\monkey.dm" #include "code\modules\mob\living\carbon\monkey\update_icons.dm" -#include "code\modules\mob\living\silicon\alarm.dm" #include "code\modules\mob\living\silicon\death.dm" #include "code\modules\mob\living\silicon\laws.dm" #include "code\modules\mob\living\silicon\login.dm" diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index dcfcb50fcb..2cff3a2338 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -484,5 +484,8 @@ datum/projectile_data temps[direction] = rstats return temps -/proc/MinutesToTicks(var/minutes as num) - return minutes * 60 * 10 +/proc/MinutesToTicks(var/minutes) + return SecondsToTicks(60 * minutes) + +/proc/SecondsToTicks(var/seconds) + return seconds * 10 diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index 8675033ef0..a842ac582d 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -26,6 +26,7 @@ datum/controller/game_controller var/powernets_cost = 0 var/nano_cost = 0 var/events_cost = 0 + var/alarms_cost = 0 var/ticker_cost = 0 var/total_cost = 0 @@ -231,6 +232,11 @@ datum/controller/game_controller/proc/process() process_events() events_cost = (world.timeofday - timer) / 10 + //ALARMS + timer = world.timeofday + process_alarms() + alarms_cost = (world.timeofday - timer) / 10 + //TICKER timer = world.timeofday last_thing_processed = ticker.type @@ -238,7 +244,7 @@ datum/controller/game_controller/proc/process() ticker_cost = (world.timeofday - timer) / 10 //TIMING - total_cost = air_cost + sun_cost + mobs_cost + diseases_cost + machines_cost + objects_cost + networks_cost + powernets_cost + nano_cost + events_cost + ticker_cost + total_cost = air_cost + sun_cost + mobs_cost + diseases_cost + machines_cost + objects_cost + networks_cost + powernets_cost + nano_cost + events_cost + alarms_cost + ticker_cost var/end_time = world.timeofday if(end_time < start_time) //why not just use world.time instead? @@ -333,9 +339,13 @@ datum/controller/game_controller/proc/process_nano() nanomanager.processing_uis.Cut(i,i+1) datum/controller/game_controller/proc/process_events() - last_thing_processed = /datum/event + last_thing_processed = /datum/event_manager event_manager.process() +datum/controller/game_controller/proc/process_alarms() + last_thing_processed = /datum/subsystem/alarm + alarm_manager.fire() + datum/controller/game_controller/proc/Recover() //Mostly a placeholder for now. var/msg = "## DEBUG: [time2text(world.timeofday)] MC restarted. Reports:\n" for(var/varname in master_controller.vars) diff --git a/code/controllers/subsystem/alarms.dm b/code/controllers/subsystem/alarms.dm new file mode 100644 index 0000000000..4684737578 --- /dev/null +++ b/code/controllers/subsystem/alarms.dm @@ -0,0 +1,27 @@ +/* /var/global/datum/alarm_handler/atmosphere_alarm = new()*/ +/var/global/datum/alarm_handler/camera_alarm = new() +/* /var/global/datum/alarm_handler/fire_alarm = new()*/ +/var/global/datum/alarm_handler/motion_alarm = new() +/* /var/global/datum/alarm_handler/power_alarm = new() */ + +/datum/subsystem/alarm + name = "Alarm" + var/list/datum/alarm/all_handlers + +/datum/subsystem/alarm/New() + all_handlers = list(camera_alarm) + +/datum/subsystem/alarm/stat_entry() + stat(null,"Alarm-[master_controller.alarms_cost]\t# [active_alarms()]") + +/datum/subsystem/alarm/fire() + for(var/datum/alarm_handler/AH in all_handlers) + AH.process() + +/datum/subsystem/alarm/proc/active_alarms() + var/total = 0 + for(var/datum/alarm_handler/AH in all_handlers) + var/list/alarms = AH.alarms + total += alarms.len + + return total diff --git a/code/controllers/subsystems.dm b/code/controllers/subsystems.dm new file mode 100644 index 0000000000..11025d8d53 --- /dev/null +++ b/code/controllers/subsystems.dm @@ -0,0 +1,46 @@ +#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;} + +/datum/subsystem + //things you will want to define + var/name //name of the subsystem + var/priority = 0 //priority affects order of initialization. Higher priorities are initialized first, lower priorities later. Can be decimal and negative values. + var/wait = 20 //time to wait (in deciseconds) between each call to fire(). Must be a positive integer. + + //things you will probably want to leave alone + var/can_fire = 0 //prevent fire() calls + var/last_fire = 0 //last world.time we called fire() + var/next_fire = 0 //scheduled world.time for next fire() + var/cpu = 0 //cpu-usage stats (somewhat vague) + var/cost = 0 //average time to execute + var/times_fired = 0 //number of times we have called fire() + +//used to initialize the subsystem BEFORE the map has loaded +/datum/subsystem/New() + +//previously, this would have been named 'process()' but that name is used everywhere for different things! +//fire() seems more suitable. This is the procedure that gets called every 'wait' deciseconds. +//fire(), and the procs it calls, SHOULD NOT HAVE ANY SLEEP OPERATIONS in them! +//YE BE WARNED! +/datum/subsystem/proc/fire() + can_fire = 0 + +//used to initialize the subsystem AFTER the map has loaded +/datum/subsystem/proc/Initialize(start_timeofday) + var/time = (world.timeofday - start_timeofday) / 10 + var/msg = "Initialized [name] SubSystem within [time] seconds" + world << "[msg]" + world.log << msg + +//hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc. +/datum/subsystem/proc/stat_entry() + stat(name, "[round(cost,0.001)]ds\t(CPU:[round(cpu,1)]%)") + +//could be used to postpone a costly subsystem for one cycle +//for instance, during cpu intensive operations like explosions +/datum/subsystem/proc/postpone() + if(next_fire - world.time < wait) + next_fire += wait + +//usually called via datum/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash) +//should attempt to salvage what it can from the old instance of subsystem +/datum/subsystem/proc/Recover() diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index 3dcba37bc0..325e2e6472 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -56,7 +56,7 @@ message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.") return -/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event")) +/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Alarm")) set category = "Debug" set name = "Debug Controller" set desc = "Debug the various periodic loop controllers for the game (be careful!)" @@ -114,5 +114,8 @@ if("Event") debug_variables(event_manager) feedback_add_details("admin_verb", "DEvent") + if("Alarm") + debug_variables(alarm_manager) + feedback_add_details("admin_verb", "DAlarm") message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") return diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 609d1a2a6b..13b7ffa34c 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -30,11 +30,17 @@ power_change() // all machines set to current power level, also updates lighting icon InitializeLighting() +/area/proc/get_cameras() + var/list/cameras = list() + for (var/area/RA in related) + for (var/obj/machinery/camera/C in RA) + cameras += C + return cameras /area/proc/poweralert(var/state, var/obj/source as obj) if (state != poweralm) poweralm = state - if(istype(source)) //Only report power alarms on the z-level where the source is located. + /*if(istype(source)) //Only report power alarms on the z-level where the source is located. var/list/cameras = list() for (var/area/RA in related) for (var/obj/machinery/camera/C in RA) @@ -54,7 +60,7 @@ if(state == 1) a.cancelAlarm("Power", src, source) else - a.triggerAlarm("Power", src, cameras, source) + a.triggerAlarm("Power", src, cameras, source) */ return /area/proc/atmosalert(danger_level, var/set_firelocks=1) @@ -71,7 +77,7 @@ if (set_firelocks && danger_level < 1 && atmosalm >= 1) //closing the doors on red and opening on green provides a bit of hysteresis that will hopefully prevent fire doors from opening and closing repeatedly due to noise air_doors_open() - + /* if (danger_level < 2 && atmosalm >= 2) for(var/area/RA in related) for(var/obj/machinery/camera/C in RA) @@ -98,7 +104,7 @@ atmosalm = danger_level for(var/area/RA in related) for (var/obj/machinery/alarm/AA in RA) - AA.update_icon() + AA.update_icon() */ return 1 return 0 @@ -141,15 +147,6 @@ else if(!D.density) spawn() D.close() - var/list/cameras = list() - for(var/area/RA in related) - for (var/obj/machinery/camera/C in RA) - cameras.Add(C) - C.network.Add("Fire Alarms") - for (var/mob/living/silicon/ai/aiPlayer in player_list) - aiPlayer.triggerAlarm("Fire", src, cameras, src) - for (var/obj/machinery/computer/station_alert/a in machines) - a.triggerAlarm("Fire", src, cameras, src) /area/proc/firereset() if (fire) @@ -164,13 +161,13 @@ else if(D.density) spawn(0) D.open() - for(var/area/RA in related) + /*for(var/area/RA in related) for (var/obj/machinery/camera/C in RA) C.network.Remove("Fire Alarms") for (var/mob/living/silicon/ai/aiPlayer in player_list) aiPlayer.cancelAlarm("Fire", src, src) for (var/obj/machinery/computer/station_alert/a in machines) - a.cancelAlarm("Fire", src, src) + a.cancelAlarm("Fire", src, src)*/ /area/proc/readyalert() if(!eject) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index d631ca46df..5d91cb6084 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -57,7 +57,7 @@ /obj/machinery/camera/Del() if(!alarm_on) triggerCameraAlarm() - + cancelCameraAlarm() ..() @@ -70,7 +70,7 @@ kick_viewers() triggerCameraAlarm() update_icon() - + spawn(900) stat &= ~EMPED cancelCameraAlarm() @@ -85,11 +85,11 @@ /obj/machinery/camera/ex_act(severity) if(src.invuln) return - + //camera dies if an explosion touches it! if(severity <= 2 || prob(50)) destroy() - + ..() //and give it the regular chance of being deleted outright @@ -174,7 +174,7 @@ if (S.current == src) O << "[U] holds \a [itemname] up to one of the cameras ..." O << browse(text("[][]", itemname, info), text("window=[]", itemname)) - + else if (istype(W, /obj/item/weapon/camera_bug)) if (!src.can_use()) user << "\blue Camera non-functional" @@ -185,7 +185,7 @@ else user << "\blue Camera bugged." src.bugged = 1 - + else if(W.damtype == BRUTE || W.damtype == BURN) //bashing cameras if (W.force >= src.toughness) visible_message("[src] has been [pick(W.attack_verb)] with [W] by [user]!") @@ -194,7 +194,7 @@ if (I.hitsound) playsound(loc, I.hitsound, 50, 1, -1) take_damage(W.force) - + else ..() @@ -221,14 +221,14 @@ if (force >= toughness && (force > toughness*4 || prob(25))) destroy() -//Used when someone breaks a camera +//Used when someone breaks a camera /obj/machinery/camera/proc/destroy() invalidateCameraCache() stat |= BROKEN kick_viewers() triggerCameraAlarm() update_icon() - + //sparks var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() spark_system.set_up(5, 0, loc) @@ -264,20 +264,14 @@ /obj/machinery/camera/proc/triggerCameraAlarm() alarm_on = 1 - if(!get_area(src)) - return - - for(var/mob/living/silicon/S in mob_list) - S.triggerAlarm("Camera", get_area(src), list(src), src) - + camera_alarm.triggerAlarm(loc, src) /obj/machinery/camera/proc/cancelCameraAlarm() - alarm_on = 0 - if(!get_area(src)) + if(wires.IsIndexCut(CAMERA_WIRE_ALARM)) return - - for(var/mob/living/silicon/S in mob_list) - S.cancelAlarm("Camera", get_area(src), src) + + alarm_on = 0 + camera_alarm.cancelAlarm(loc, src) //if false, then the camera is listed as DEACTIVATED and cannot be used /obj/machinery/camera/proc/can_use() @@ -355,7 +349,7 @@ /obj/machinery/camera/interact(mob/living/user as mob) if(!panel_open || istype(user, /mob/living/silicon/ai)) return - + if(stat & BROKEN) user << "\The [src] is broken." return diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm index 0c6f7d95a7..f14608b1d4 100644 --- a/code/game/machinery/camera/motion.dm +++ b/code/game/machinery/camera/motion.dm @@ -45,8 +45,7 @@ if (!status || (stat & NOPOWER)) return 0 if (detectTime == -1) - for (var/mob/living/silicon/aiPlayer in player_list) - aiPlayer.cancelAlarm("Motion", get_area(src), src) + motion_alarm.cancelAlarm(loc, src) detectTime = 0 return 1 @@ -54,8 +53,7 @@ if (!status || (stat & NOPOWER)) return 0 if (!detectTime) return 0 - for (var/mob/living/silicon/aiPlayer in player_list) - aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src) + motion_alarm.triggerAlarm(loc, src) detectTime = -1 return 1 diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 2067bd43a0..b1100fd77c 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -3,6 +3,8 @@ /proc/invalidateCameraCache() for(var/obj/machinery/computer/security/s in world) s.camera_cache = null + for(var/datum/alarm/A in alarm_manager.active_alarms()) + A.cameras = null /obj/machinery/computer/security name = "security camera monitor" diff --git a/code/global.dm b/code/global.dm index c5fd821f79..13a62b38ce 100644 --- a/code/global.dm +++ b/code/global.dm @@ -174,8 +174,9 @@ var/gravity_is_on = 1 var/join_motd = null var/forceblob = 0 -var/datum/nanomanager/nanomanager = new() // NanoManager, the manager for Nano UIs. -var/datum/event_manager/event_manager = new() // Event Manager, the manager for events. +var/datum/nanomanager/nanomanager = new() // NanoManager, the manager for Nano UIs. +var/datum/event_manager/event_manager = new() // Event Manager, the manager for events. +var/datum/subsystem/alarm/alarm_manager = new() // Alarm Manager, the manager for alarms. var/list/awaydestinations = list() // Away missions. A list of landmarks that the warpgate can take you to. diff --git a/code/modules/alarm/alarm.dm b/code/modules/alarm/alarm.dm new file mode 100644 index 0000000000..0bbeed527d --- /dev/null +++ b/code/modules/alarm/alarm.dm @@ -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() diff --git a/code/modules/alarm/alarm_handler.dm b/code/modules/alarm/alarm_handler.dm new file mode 100644 index 0000000000..3fd21fc4a0 --- /dev/null +++ b/code/modules/alarm/alarm_handler.dm @@ -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) diff --git a/code/modules/alarm/atmosphere_alarm.dm b/code/modules/alarm/atmosphere_alarm.dm new file mode 100644 index 0000000000..7aad426421 --- /dev/null +++ b/code/modules/alarm/atmosphere_alarm.dm @@ -0,0 +1,2 @@ +/datum/alarm_handler/atmosphere + category = "Atmosphere" diff --git a/code/modules/alarm/camera_alarm.dm b/code/modules/alarm/camera_alarm.dm new file mode 100644 index 0000000000..4624625043 --- /dev/null +++ b/code/modules/alarm/camera_alarm.dm @@ -0,0 +1,2 @@ +/datum/alarm_handler/camera + category = "Camera" \ No newline at end of file diff --git a/code/modules/alarm/fire_alarm.dm b/code/modules/alarm/fire_alarm.dm new file mode 100644 index 0000000000..e654b966b6 --- /dev/null +++ b/code/modules/alarm/fire_alarm.dm @@ -0,0 +1,2 @@ +/datum/alarm_handler/fire_alarm + category = "Fire" diff --git a/code/modules/alarm/motion_alarm.dm b/code/modules/alarm/motion_alarm.dm new file mode 100644 index 0000000000..f51ef3c27b --- /dev/null +++ b/code/modules/alarm/motion_alarm.dm @@ -0,0 +1,2 @@ +/datum/alarm_handler/motion + category = "Motion" diff --git a/code/modules/alarm/power_alarm.dm b/code/modules/alarm/power_alarm.dm new file mode 100644 index 0000000000..8571dbac61 --- /dev/null +++ b/code/modules/alarm/power_alarm.dm @@ -0,0 +1,2 @@ +/datum/alarm_handler/power + category = "Power" diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 3278198723..376031fe4d 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -324,31 +324,8 @@ var/list/ai_verbs_default = list( set category = "AI Commands" set name = "Show Alerts" - var/dat = "Current Station Alerts\n" - dat += "Close

" - for (var/cat in alarms) - dat += text("[]
\n", cat) - var/list/alarmlist = alarms[cat] - if (alarmlist.len) - for (var/area_name in alarmlist) - var/datum/alarm/alarm = alarmlist[area_name] - dat += "" - - var/cameratext = "" - if (alarm.cameras) - for (var/obj/machinery/camera/I in alarm.cameras) - cameratext += text("[][]", (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 += "
\n" - else - dat += "-- All Systems Nominal
\n" - dat += "
\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 == "")? "" : "|"][C.c_tag]" - - 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" diff --git a/code/modules/mob/living/silicon/alarm.dm b/code/modules/mob/living/silicon/alarm.dm deleted file mode 100644 index ee505fae5c..0000000000 --- a/code/modules/mob/living/silicon/alarm.dm +++ /dev/null @@ -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 += "\[Show Alerts\]" - 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 += "\[Show Alerts\]" - 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 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 6b0509eea1..025f1ef0c2 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -450,25 +450,8 @@ var/list/robot_verbs_default = list( /mob/living/silicon/robot/proc/robot_alerts() - var/dat = "Current Station Alerts\n" - dat += "Close

" - for (var/cat in alarms) - dat += text("[cat]
\n") - var/list/alarmlist = alarms[cat] - if (alarmlist.len) - for (var/area_name in alarmlist) - var/datum/alarm/alarm = alarmlist[area_name] - dat += "" - dat += text("-- [area_name]") - if (alarm.sources.len > 1) - dat += text("- [alarm.sources.len] sources") - dat += "
\n" - else - dat += "-- All Systems Nominal
\n" - dat += "
\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 diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index bda7d984e2..af7881986b 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -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 diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 15347c2580..12c9f314e4 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -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)