From 5578afa07c23454d662a057c6f2a203da9b5ccd9 Mon Sep 17 00:00:00 2001 From: PsiOmega Date: Tue, 17 Feb 2015 16:53:08 +0100 Subject: [PATCH] General update. NanoUI interface sorted. Accessible by AI, borgs, and through consoles. Automatic alarm resets in case of lost sources. --- baystation12.dme | 4 +- code/__HELPERS/lists.dm | 4 + code/controllers/subsystem/alarms.dm | 26 ++-- code/game/machinery/alarm.dm | 2 + code/game/machinery/camera/camera.dm | 25 ++-- code/game/machinery/camera/motion.dm | 2 +- code/game/machinery/computer/camera.dm | 26 +--- code/game/machinery/computer/station_alert.dm | 134 +++++------------- code/modules/alarm/alarm.dm | 65 ++++++++- code/modules/alarm/alarm_handler.dm | 115 ++++++++------- code/modules/alarm/fire_alarm.dm | 2 +- code/modules/mob/living/silicon/ai/ai.dm | 19 +-- code/modules/mob/living/silicon/ai/nano.dm | 27 ---- .../mob/living/silicon/ai/subsystems.dm | 44 ++++++ .../modules/mob/living/silicon/robot/robot.dm | 32 ++--- .../mob/living/silicon/robot/subsystems.dm | 9 ++ code/modules/mob/living/silicon/silicon.dm | 10 +- code/modules/mob/mob.dm | 34 +++-- code/modules/mob/mob_helpers.dm | 13 ++ code/modules/nano/modules/alarm_monitor.dm | 86 +++++++++++ code/modules/nano/modules/rcon.dm | 2 +- nano/css/shared.css | 6 + nano/templates/alarm_monitor.tmpl | 37 +++++ 23 files changed, 439 insertions(+), 285 deletions(-) delete mode 100644 code/modules/mob/living/silicon/ai/nano.dm create mode 100644 code/modules/mob/living/silicon/ai/subsystems.dm create mode 100644 code/modules/mob/living/silicon/robot/subsystems.dm create mode 100644 code/modules/nano/modules/alarm_monitor.dm create mode 100644 nano/templates/alarm_monitor.tmpl diff --git a/baystation12.dme b/baystation12.dme index 7e8f14d39e..fcfb95c66e 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1144,8 +1144,8 @@ #include "code\modules\mob\living\silicon\ai\life.dm" #include "code\modules\mob\living\silicon\ai\login.dm" #include "code\modules\mob\living\silicon\ai\logout.dm" -#include "code\modules\mob\living\silicon\ai\nano.dm" #include "code\modules\mob\living\silicon\ai\say.dm" +#include "code\modules\mob\living\silicon\ai\subsystems.dm" #include "code\modules\mob\living\silicon\ai\freelook\cameranet.dm" #include "code\modules\mob\living\silicon\ai\freelook\chunk.dm" #include "code\modules\mob\living\silicon\ai\freelook\eye.dm" @@ -1178,6 +1178,7 @@ #include "code\modules\mob\living\silicon\robot\robot_items.dm" #include "code\modules\mob\living\silicon\robot\robot_modules.dm" #include "code\modules\mob\living\silicon\robot\robot_movement.dm" +#include "code\modules\mob\living\silicon\robot\subsystems.dm" #include "code\modules\mob\living\silicon\robot\drone\drone.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_abilities.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_console.dm" @@ -1236,6 +1237,7 @@ #include "code\modules\nano\nanomapgen.dm" #include "code\modules\nano\nanoprocs.dm" #include "code\modules\nano\nanoui.dm" +#include "code\modules\nano\modules\alarm_monitor.dm" #include "code\modules\nano\modules\crew_monitor.dm" #include "code\modules\nano\modules\power_monitor.dm" #include "code\modules\nano\modules\rcon.dm" diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 1e8ccb6a4d..9fd6a8c0e9 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -596,3 +596,7 @@ datum/proc/dd_SortValue() /obj/machinery/camera/dd_SortValue() return "[c_tag]" + +/datum/alarm/dd_SortValue() + return "[sanitize(last_name)]" + diff --git a/code/controllers/subsystem/alarms.dm b/code/controllers/subsystem/alarms.dm index 4684737578..a13e60782d 100644 --- a/code/controllers/subsystem/alarms.dm +++ b/code/controllers/subsystem/alarms.dm @@ -1,27 +1,33 @@ -/* /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() */ +// We manually initialize the alarm handlers instead of looping over all existing types +// to make it possible to write: camera.triggerAlarm() rather than alarm_manager.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof. +/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new() +/var/global/datum/alarm_handler/camera/camera_alarm = new() +/var/global/datum/alarm_handler/fire/fire_alarm = new() +/var/global/datum/alarm_handler/motion/motion_alarm = new() +/var/global/datum/alarm_handler/power/power_alarm = new() /datum/subsystem/alarm name = "Alarm" var/list/datum/alarm/all_handlers /datum/subsystem/alarm/New() - all_handlers = list(camera_alarm) + all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm) /datum/subsystem/alarm/stat_entry() - stat(null,"Alarm-[master_controller.alarms_cost]\t# [active_alarms()]") + stat(null,"Alarm-[master_controller.alarms_cost]\t#[number_of_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 + var/list/all_alarms = new for(var/datum/alarm_handler/AH in all_handlers) var/list/alarms = AH.alarms - total += alarms.len + all_alarms += alarms - return total + return all_alarms + +/datum/subsystem/alarm/proc/number_of_active_alarms() + var/list/alarms = active_alarms() + return alarms.len diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index 2ffdcc6e2f..c9a10bc728 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -460,10 +460,12 @@ if(alert_level==2) alert_signal.data["alert"] = "severe" + atmosphere_alarm.triggerAlarm(src.loc, src) else if (alert_level==1) alert_signal.data["alert"] = "minor" else if (alert_level==0) alert_signal.data["alert"] = "clear" + atmosphere_alarm.clearAlarm(src.loc, src) frequency.post_signal(src, alert_signal) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index d6640f6534..77f41cb2eb 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -53,13 +53,6 @@ ASSERT(src.network.len > 0) ..() -/obj/machinery/camera/Del() - if(!alarm_on) - triggerCameraAlarm() - - cancelCameraAlarm() - ..() - /obj/machinery/camera/emp_act(severity) if(!isEmpProof()) if(prob(100/severity)) @@ -67,7 +60,7 @@ stat |= EMPED SetLuminosity(0) kick_viewers() - triggerCameraAlarm() + triggerCameraAlarm(10 * severity) update_icon() spawn(900) @@ -261,16 +254,16 @@ else icon_state = initial(icon_state) -/obj/machinery/camera/proc/triggerCameraAlarm() +/obj/machinery/camera/proc/triggerCameraAlarm(var/duration = 0) alarm_on = 1 - camera_alarm.triggerAlarm(loc, src) + camera_alarm.triggerAlarm(loc, src, duration) /obj/machinery/camera/proc/cancelCameraAlarm() if(wires.IsIndexCut(CAMERA_WIRE_ALARM)) return alarm_on = 0 - camera_alarm.cancelAlarm(loc, src) + camera_alarm.clearAlarm(loc, src) //if false, then the camera is listed as DEACTIVATED and cannot be used /obj/machinery/camera/proc/can_use() @@ -355,3 +348,13 @@ user.set_machine(src) wires.Interact(user) + +/obj/machinery/camera/proc/nano_structure() + var/cam[0] + cam["name"] = sanitize(c_tag) + cam["deact"] = !can_use() + cam["camera"] = "\ref[src]" + cam["x"] = x + cam["y"] = y + cam["z"] = z + return cam diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm index f14608b1d4..636f114de7 100644 --- a/code/game/machinery/camera/motion.dm +++ b/code/game/machinery/camera/motion.dm @@ -45,7 +45,7 @@ if (!status || (stat & NOPOWER)) return 0 if (detectTime == -1) - motion_alarm.cancelAlarm(loc, src) + motion_alarm.clearAlarm(loc, src) detectTime = 0 return 1 diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index b1100fd77c..8cb58a14cb 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -3,7 +3,7 @@ /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()) + for(var/datum/alarm/A in world) A.cameras = null /obj/machinery/computer/security @@ -45,33 +45,17 @@ if(!can_access_camera(C)) continue - var/cam[0] - cam["name"] = sanitize(C.c_tag) - cam["deact"] = !C.can_use() - cam["camera"] = "\ref[C]" - cam["x"] = C.x - cam["y"] = C.y - cam["z"] = C.z - + var/cam = C.nano_structure() cameras[++cameras.len] = cam if(C == current) data["current"] = cam - var/list/camera_list = list("cameras" = cameras) - camera_cache=list2json(camera_list) - + var/list/camera_list = list("cameras" = cameras) + camera_cache=list2json(camera_list) else if(current) - var/cam[0] - cam["name"] = current.c_tag - cam["deact"] = !current.can_use() - cam["camera"] = "\ref[current]" - cam["x"] = current.x - cam["y"] = current.y - cam["z"] = current.z - - data["current"] = cam + data["current"] = current.nano_structure() if(ui) diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm index 028be6e3a3..f585162ae9 100644 --- a/code/game/machinery/computer/station_alert.dm +++ b/code/game/machinery/computer/station_alert.dm @@ -5,106 +5,42 @@ icon_state = "alert:0" circuit = "/obj/item/weapon/circuitboard/stationalert" var/alarms = list("Fire"=list(), "Atmosphere"=list(), "Power"=list()) + var/obj/nano_module/alarm_monitor/engineering/alarm_monitor +/obj/machinery/computer/station_alert/New() + ..() + alarm_monitor = new(src) + alarm_monitor.register(src, /obj/machinery/computer/station_alert/update_icon) - attack_ai(mob/user) - add_fingerprint(user) - if(stat & (BROKEN|NOPOWER)) - return - interact(user) +/obj/machinery/computer/station_alert/Del() + alarm_monitor.unregister(src) + ..() + +/obj/machinery/computer/station_alert/attack_ai(mob/user) + add_fingerprint(user) + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + return + +/obj/machinery/computer/station_alert/attack_hand(mob/user) + add_fingerprint(user) + if(stat & (BROKEN|NOPOWER)) + return + interact(user) + return + +/obj/machinery/computer/station_alert/interact(mob/user) + alarm_monitor.ui_interact(user) + +/obj/machinery/computer/station_alert/update_icon() + ..() + if(stat & (BROKEN|NOPOWER)) return - - attack_hand(mob/user) - add_fingerprint(user) - if(stat & (BROKEN|NOPOWER)) - return - interact(user) - return - - - interact(mob/user) - usr.set_machine(src) - var/dat = "Current Station Alerts\n" - dat += "Close

" - for (var/cat in src.alarms) - dat += text("[]
\n", cat) - var/list/L = src.alarms[cat] - if (L.len) - for (var/alarm in L) - var/list/alm = L[alarm] - var/area/A = alm[1] - var/list/sources = alm[3] - dat += "" - dat += "• " - dat += "[A.name]" - if (sources.len > 1) - dat += text(" - [] sources", sources.len) - dat += "
\n" - else - dat += "-- All Systems Nominal
\n" - dat += "
\n" - user << browse(dat, "window=alerts") - onclose(user, "alerts") - - - Topic(href, href_list) - if(..()) - return - return - - - proc/triggerAlarm(var/class, area/A, var/O, var/alarmsource) - if(stat & (BROKEN)) - return - var/list/L = src.alarms[class] - for (var/I in L) - if (I == A.name) - var/list/alarm = L[I] - var/list/sources = alarm[3] - if (!(alarmsource in sources)) - sources += alarmsource - return 1 - var/obj/machinery/camera/C = null - var/list/CL = null - if (O && istype(O, /list)) - CL = O - if (CL.len == 1) - C = CL[1] - else if (O && istype(O, /obj/machinery/camera)) - C = O - L[A.name] = list(A, (C) ? C : O, list(alarmsource)) - return 1 - - - proc/cancelAlarm(var/class, area/A as area, obj/origin) - if(stat & (BROKEN)) - return - var/list/L = src.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 - - - process() - if(stat & (BROKEN|NOPOWER)) - icon_state = "atmos0" - return - var/active_alarms = 0 - for (var/cat in src.alarms) - var/list/L = src.alarms[cat] - if(L.len) active_alarms = 1 - if(active_alarms) - icon_state = "alert:2" - else - icon_state = "alert:0" - ..() - return + var/list/alarms = alarm_monitor.active_alarms() + if(alarms.len) + icon_state = "alert:2" + else + icon_state = "alert:0" + return diff --git a/code/modules/alarm/alarm.dm b/code/modules/alarm/alarm.dm index 0bbeed527d..623c38c503 100644 --- a/code/modules/alarm/alarm.dm +++ b/code/modules/alarm/alarm.dm @@ -1,3 +1,5 @@ +#define ALARM_RESET_DELAY 100 // How long will the alarm/trigger remain active once origin/source has been found to be gone? + /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) @@ -7,8 +9,8 @@ /datum/alarm_source/New(var/atom/source) src.source = source - source_name = source.name start_time = world.time + source_name = source.get_source_name() /datum/alarm var/atom/origin //Used to identify the alarm area. @@ -16,24 +18,42 @@ 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). + var/area/last_name //The last acquired name, used should origin be lost + var/area/last_camera_area //The last area in which cameras where fetched, used to see if the camera list should be updated. + var/end_time //Used to set when this alarm should clear, in case the origin is lost. /datum/alarm/New(var/atom/origin, var/atom/source, var/duration) src.origin = origin - last_area = alarm_area() + + cameras() // Sets up both cameras and last alarm area. set_duration(source, duration) +/datum/alarm/proc/process() + // Has origin gone missing? + if(!origin && !end_time) + end_time = world.time + ALARM_RESET_DELAY + for(var/datum/alarm_source/AS in sources) + // Has the alarm passed its best before date? + if((AS.end_time && world.time > AS.end_time) || (AS.duration && world.time > (AS.start_time + AS.duration))) + sources -= AS + // Has the source gone missing? Then reset the normal duration and set end_time + if(!AS.source && !AS.end_time) // end_time is used instead of duration to ensure the reset doesn't remain in the future indefinetely. + AS.duration = 0 + AS.end_time = world.time + ALARM_RESET_DELAY + /datum/alarm/proc/set_duration(var/atom/source, var/duration) - var/datum/alarm_source/AS = sources[source] + var/datum/alarm_source/AS = sources_assoc[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) + duration = SecondsToTicks(duration) AS.duration = duration /datum/alarm/proc/clear(var/source) - var/datum/alarm_source/AS = sources[source] + var/datum/alarm_source/AS = sources_assoc[source] sources -= AS sources_assoc -= source @@ -44,22 +64,51 @@ last_area = origin.get_alarm_area() return last_area -/datum/alarm/proc/cameras() +/datum/alarm/proc/alarm_name() if(!origin) - return list() + return last_name + last_name = origin.get_alarm_name() + return last_name + +/datum/alarm/proc/cameras() + // If the alarm origin has changed area, for example a borg containing an alarming camera, reset the list of cameras + if(cameras && (last_camera_area != alarm_area())) + cameras = null + + // The list of cameras is also reset by /proc/invalidateCameraCache() if(!cameras) - cameras = origin.get_alarm_cameras() + cameras = origin ? origin.get_alarm_cameras() : last_area.get_alarm_cameras() + last_camera_area = last_area return cameras +/****************** +* Assisting procs * +******************/ /atom/proc/get_alarm_area() return get_area(src) /area/get_alarm_area() return src +/atom/proc/get_alarm_name() + var/area/A = get_area(src) + return A.name + +/area/get_alarm_name() + return name + +/mob/get_alarm_name() + return name + +/atom/proc/get_source_name() + return name + +/obj/machinery/camera/get_source_name() + return c_tag + /atom/proc/get_alarm_cameras() var/area/A = get_area(src) return A.get_cameras() @@ -76,3 +125,5 @@ /mob/living/silicon/robot/syndicate/get_alarm_cameras() return list() + +#undef ALARM_LOSS_DELAY diff --git a/code/modules/alarm/alarm_handler.dm b/code/modules/alarm/alarm_handler.dm index 3fd21fc4a0..9c92a7793a 100644 --- a/code/modules/alarm/alarm_handler.dm +++ b/code/modules/alarm/alarm_handler.dm @@ -1,64 +1,82 @@ -#define ALARM_ORIGIN_LOST "Origin Lost" +#define ALARM_RAISED 1 +#define ALARM_CLEARED 0 /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. + var/list/datum/alarm/alarms = new // All alarms, to handle cases when an 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. + var/list/listeners = new // A list of all objects interested in alarm changes. /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.. - */ + A.process() + check_alarm_cleared(A) /datum/alarm_handler/proc/triggerAlarm(var/atom/origin, var/atom/source, var/duration = 0) + var/new_alarm //Proper origin and source mandatory if(!origin || !source) return + new_alarm = 0 //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] + var/datum/alarm/existing = alarms_assoc[origin] if(existing) existing.set_duration(source, duration) else existing = new/datum/alarm(origin, source, duration) + new_alarm = 1 alarms |= existing - alarms_assoc[alarm_key] = existing + alarms_assoc[origin] = existing + if(new_alarm) + alarms = dd_sortedObjectList(alarms) + notify_listeners(existing, ALARM_RAISED) -/datum/alarm_handler/proc/cancelAlarm(var/atom/origin, var/source) + return new_alarm + +/datum/alarm_handler/proc/clearAlarm(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] + var/datum/alarm/existing = alarms_assoc[origin] if(existing) existing.clear(source) - if (!existing.sources.len) - alarms -= existing - alarms_assoc -= alarm_key + return check_alarm_cleared(existing) -/atom/proc/get_alarm_key() - return src +/datum/alarm_handler/proc/check_alarm_cleared(var/datum/alarm/alarm) + if ((alarm.end_time && world.time > alarm.end_time) || !alarm.sources.len) + alarms -= alarm + alarms_assoc -= alarm.origin + notify_listeners(alarm, ALARM_CLEARED) + return 1 + return 0 -/turf/get_alarm_key() - return get_area(src) +/datum/alarm_handler/proc/register(var/object, var/procName) + listeners[object] = procName +/datum/alarm_handler/proc/unregister(var/object) + listeners -= object + +/datum/alarm_handler/proc/notify_listeners(var/alarm, var/was_raised) + for(var/listener in listeners) + call(listener, listeners[listener])(src, alarm, was_raised) + +/******** +* DEBUG * +********/ /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" + var/obj/nano_module/alarm_monitor/ai/alarm_monitor + +/obj/item/device/alarm_debug/New() + ..() + alarm_monitor = new(src) /obj/item/device/alarm_debug/loc name = "An alarm debug tool - Loc" @@ -67,46 +85,33 @@ set name = "Alarm" set category = "Debug" usr << "Raising alarm" - camera_alarm.triggerAlarm(src, src) + fire_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]" + usr << "Clearing alarm" + fire_alarm.clearAlarm(src, src) /obj/item/device/alarm_debug/loc/alarm() set name = "Alarm" set category = "Debug" usr << "Raising alarm" - camera_alarm.triggerAlarm(src.loc, src) + fire_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) + fire_alarm.clearAlarm(src.loc, src) + +/obj/item/device/alarm_debug/verb/nano() + set name = "Nano" + set category = "Debug" + alarm_monitor.ui_interact(usr) + +/obj/item/device/alarm_debug/attack_self(var/mob/user) + alarm_monitor.ui_interact(user) + +#undef ALARM_RAISED +#undef ALARM_CLEARED diff --git a/code/modules/alarm/fire_alarm.dm b/code/modules/alarm/fire_alarm.dm index e654b966b6..1b7256517e 100644 --- a/code/modules/alarm/fire_alarm.dm +++ b/code/modules/alarm/fire_alarm.dm @@ -1,2 +1,2 @@ -/datum/alarm_handler/fire_alarm +/datum/alarm_handler/fire category = "Fire" diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 306be81c88..a0781d7073 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -3,7 +3,6 @@ var/list/ai_list = list() var/list/ai_verbs_default = list( - /mob/living/silicon/ai/proc/ai_alerts, /mob/living/silicon/ai/proc/ai_announcement, /mob/living/silicon/ai/proc/ai_call_shuttle, // /mob/living/silicon/ai/proc/ai_recall_shuttle, @@ -23,10 +22,7 @@ var/list/ai_verbs_default = list( /mob/living/silicon/ai/proc/sensor_mode, /mob/living/silicon/ai/proc/show_laws_verb, /mob/living/silicon/ai/proc/toggle_acceleration, - /mob/living/silicon/ai/proc/toggle_camera_light, - /mob/living/silicon/ai/proc/nano_rcon, - /mob/living/silicon/ai/proc/nano_crew_monitor, - /mob/living/silicon/ai/proc/nano_power_monitor + /mob/living/silicon/ai/proc/toggle_camera_light ) //Not sure why this is necessary... @@ -83,9 +79,11 @@ var/list/ai_verbs_default = list( /mob/living/silicon/ai/proc/add_ai_verbs() src.verbs |= ai_verbs_default + src.verbs |= ai_verbs_subsystems /mob/living/silicon/ai/proc/remove_ai_verbs() src.verbs -= ai_verbs_default + src.verbs -= ai_verbs_subsystems /mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0) announcement = new() @@ -166,8 +164,6 @@ var/list/ai_verbs_default = list( hud_list[IMPTRACK_HUD] = image('icons/mob/hud.dmi', src, "hudblank") hud_list[SPECIALROLE_HUD] = image('icons/mob/hud.dmi', src, "hudblank") - init_subsystems() - ai_list += src ..() return @@ -325,13 +321,6 @@ var/list/ai_verbs_default = list( if(malf && malf.apcs >= 3) stat(null, "Time until station control secured: [max(malf.AI_win_timeleft/(malf.apcs/3), 0)] seconds") -/mob/living/silicon/ai/proc/ai_alerts() - set category = "AI Commands" - set name = "Show Alerts" - - //PsiFix - //nano_alarm.ui_interact(usr) - // this verb lets the ai see the stations manifest /mob/living/silicon/ai/proc/ai_roster() set category = "AI Commands" @@ -428,7 +417,7 @@ var/list/ai_verbs_default = list( if (href_list["switchcamera"]) switchCamera(locate(href_list["switchcamera"])) in cameranet.cameras if (href_list["showalerts"]) - ai_alerts() + subsystem_alarm_monitor() //Carn: holopad requests if (href_list["jumptoholopad"]) var/obj/machinery/hologram/holopad/H = locate(href_list["jumptoholopad"]) diff --git a/code/modules/mob/living/silicon/ai/nano.dm b/code/modules/mob/living/silicon/ai/nano.dm deleted file mode 100644 index 8572c8ec59..0000000000 --- a/code/modules/mob/living/silicon/ai/nano.dm +++ /dev/null @@ -1,27 +0,0 @@ -var/obj/nano_module/crew_monitor/crew_monitor -var/obj/nano_module/rcon/rcon -var/obj/nano_module/power_monitor/power_monitor - -/mob/living/silicon/ai/proc/init_subsystems() - crew_monitor = new(src) - rcon = new(src) - power_monitor = new(src) - -/mob/living/silicon/ai/proc/nano_crew_monitor() - set category = "AI Subystems" - set name = "Crew Monitor" - - crew_monitor.ui_interact(usr) - -/mob/living/silicon/ai/proc/nano_power_monitor() - set category = "AI Subystems" - set name = "Power Monitor" - - power_monitor.ui_interact(usr) - - -/mob/living/silicon/ai/proc/nano_rcon() - set category = "AI Subystems" - set name = "RCON" - - rcon.ui_interact(usr) diff --git a/code/modules/mob/living/silicon/ai/subsystems.dm b/code/modules/mob/living/silicon/ai/subsystems.dm new file mode 100644 index 0000000000..3ef229712e --- /dev/null +++ b/code/modules/mob/living/silicon/ai/subsystems.dm @@ -0,0 +1,44 @@ +var/list/ai_verbs_subsystems = list( + /mob/living/silicon/ai/proc/subsystem_alarm_monitor, + /mob/living/silicon/ai/proc/subsystem_crew_monitor, + /mob/living/silicon/ai/proc/subsystem_power_monitor, + /mob/living/silicon/ai/proc/subsystem_rcon +) + +/mob/living/silicon/ai + var/ + var/obj/nano_module/crew_monitor/crew_monitor + var/obj/nano_module/rcon/rcon + var/obj/nano_module/power_monitor/power_monitor + +/mob/living/silicon/ai/init_subsystems() + ..() + del(alarm_monitor) + alarm_monitor = new/obj/nano_module/alarm_monitor/ai(src) + crew_monitor = new(src) + rcon = new(src) + power_monitor = new(src) + +/mob/living/silicon/ai/proc/subsystem_alarm_monitor() + set name = "Alarm Monitor" + set category = "AI Subystems" + + alarm_monitor.ui_interact(usr) + +/mob/living/silicon/ai/proc/subsystem_crew_monitor() + set category = "AI Subystems" + set name = "Crew Monitor" + + crew_monitor.ui_interact(usr) + +/mob/living/silicon/ai/proc/subsystem_power_monitor() + set category = "AI Subystems" + set name = "Power Monitor" + + power_monitor.ui_interact(usr) + +/mob/living/silicon/ai/proc/subsystem_rcon() + set category = "AI Subystems" + set name = "RCON" + + rcon.ui_interact(usr) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 025f1ef0c2..0f04f741c8 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -437,22 +437,12 @@ var/list/robot_verbs_default = list( updatename() updateicon() -/mob/living/silicon/robot/verb/cmd_robot_alerts() - set category = "Robot Commands" - set name = "Show Alerts" - robot_alerts() - // this verb lets cyborgs see the stations manifest /mob/living/silicon/robot/verb/cmd_station_manifest() set category = "Robot Commands" set name = "Show Crew Manifest" show_station_manifest() - -/mob/living/silicon/robot/proc/robot_alerts() - //PsiFix - //nano_alarm.ui_interact(usr) - /mob/living/silicon/robot/proc/self_diagnosis() if(!is_component_functioning("diagnosis unit")) return null @@ -1004,30 +994,31 @@ var/list/robot_verbs_default = list( /mob/living/silicon/robot/Topic(href, href_list) if(..()) - return + return 1 if(usr != src) - return + return 1 if (href_list["showalerts"]) - robot_alerts() - return + subsystem_alarm_monitor() + return 1 if (href_list["mod"]) var/obj/item/O = locate(href_list["mod"]) if (istype(O) && (O.loc == src)) O.attack_self(src) + return 1 if (href_list["act"]) var/obj/item/O = locate(href_list["act"]) if (!istype(O)) - return + return 1 if(!((O in src.module.modules) || (O == src.module.emag))) - return + return 1 if(activated(O)) src << "Already activated" - return + return 1 if(!module_state_1) module_state_1 = O O.layer = 20 @@ -1049,6 +1040,7 @@ var/list/robot_verbs_default = list( else src << "You need to disable a module first!" installed_modules() + return 1 if (href_list["deact"]) var/obj/item/O = locate(href_list["deact"]) @@ -1067,6 +1059,7 @@ var/list/robot_verbs_default = list( else src << "Module isn't activated" installed_modules() + return 1 if (href_list["lawc"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite var/L = text2num(href_list["lawc"]) @@ -1075,6 +1068,7 @@ var/list/robot_verbs_default = list( if ("No") lawcheck[L+1] = "Yes" // src << text ("Switching Law [L]'s report status to []", lawcheck[L+1]) checklaws() + return 1 if (href_list["lawi"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite var/L = text2num(href_list["lawi"]) @@ -1083,9 +1077,11 @@ var/list/robot_verbs_default = list( if ("No") ioncheck[L] = "Yes" // src << text ("Switching Law [L]'s report status to []", lawcheck[L+1]) checklaws() + return 1 if (href_list["laws"]) // With how my law selection code works, I changed statelaws from a verb to a proc, and call it through my law selection panel. --NeoFite statelaws() + return 1 return /mob/living/silicon/robot/proc/radio_menu() @@ -1218,9 +1214,11 @@ var/list/robot_verbs_default = list( /mob/living/silicon/robot/proc/add_robot_verbs() src.verbs |= robot_verbs_default + src.verbs |= robot_verbs_subsystems /mob/living/silicon/robot/proc/remove_robot_verbs() src.verbs -= robot_verbs_default + src.verbs -= robot_verbs_subsystems // Uses power from cyborg's cell. Returns 1 on success or 0 on failure. // Properly converts using CELLRATE now! Amount is in Joules. diff --git a/code/modules/mob/living/silicon/robot/subsystems.dm b/code/modules/mob/living/silicon/robot/subsystems.dm new file mode 100644 index 0000000000..4750828544 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/subsystems.dm @@ -0,0 +1,9 @@ +var/list/robot_verbs_subsystems = list( + /mob/living/silicon/robot/proc/subsystem_alarm_monitor +) + +/mob/living/silicon/robot/proc/subsystem_alarm_monitor() + set name = "Alarm Monitor" + set category = "Robot Subystems" + + alarm_monitor.ui_interact(usr) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index af7881986b..a4ee540c2b 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -22,6 +22,9 @@ var/obj/item/device/camera/siliconcam/aiCamera = null //photography var/local_transmit //If set, can only speak to others of the same type within a short range. + // Subsystems + var/obj/nano_module/alarm_monitor = null + var/sensor_mode = 0 //Determines the current HUD. #define SEC_HUD 1 //Security HUD mode @@ -30,6 +33,7 @@ /mob/living/silicon/New() ..() add_language("Galactic Common") + init_subsystems() /mob/living/silicon/proc/SetName(pickedName as text) real_name = pickedName @@ -244,7 +248,8 @@ return 1 /mob/living/silicon/Topic(href, href_list) - ..() + if(..()) + return 1 if (href_list["lawr"]) // Selects on which channel to state laws var/list/channels = list(MAIN_CHANNEL) @@ -283,3 +288,6 @@ adjustBruteLoss(30) updatehealth() + +/mob/living/silicon/proc/init_subsystems() + alarm_monitor = new/obj/nano_module/alarm_monitor/borg(src) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index a6ba0bed0a..323cdfaf8b 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -792,27 +792,25 @@ note dizziness decrements automatically in the mob's Life() proc. /mob/Stat() ..() - if(statpanel("MC")) //not looking at that panel - - if(client && client.holder) + if(client && client.holder) + if(statpanel("Status")) stat(null,"Location:\t([x], [y], [z])") stat(null,"CPU:\t[world.cpu]") stat(null,"Instances:\t[world.contents.len]") - - if(master_controller) - stat(null,"MasterController-[last_tick_duration] ([master_controller.processing?"On":"Off"]-[controller_iteration])") - stat(null,"Air-[master_controller.air_cost]\tSun-[master_controller.sun_cost]") - stat(null,"Mob-[master_controller.mobs_cost]\t#[mob_list.len]") - stat(null,"Dis-[master_controller.diseases_cost]\t#[active_diseases.len]") - stat(null,"Mch-[master_controller.machines_cost]\t#[machines.len]") - 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") + if(statpanel("MC") && master_controller) + stat(null,"MasterController-[last_tick_duration] ([master_controller.processing?"On":"Off"]-[controller_iteration])") + stat(null,"Air-[master_controller.air_cost]\tSun-[master_controller.sun_cost]") + stat(null,"Mob-[master_controller.mobs_cost]\t#[mob_list.len]") + stat(null,"Dis-[master_controller.diseases_cost]\t#[active_diseases.len]") + stat(null,"Mch-[master_controller.machines_cost]\t#[machines.len]") + 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") if(listed_turf && client) if(!TurfAdjacent(listed_turf)) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 3c983bcc22..d064ee67b4 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -547,3 +547,16 @@ proc/is_blind(A) say_dead_direct("The ghost of [name] now [pick("skulks","lurks","prowls","creeps","stalks")] among the dead. [message]") else say_dead_direct("[name] no longer [pick("skulks","lurks","prowls","creeps","stalks")] in the realm of the dead. [message]") + +/mob/proc/switch_to_camera(var/obj/machinery/camera/C) + if (!C.can_use() || stat || (get_dist(C, src) > 1 || machine != src || blinded || !canmove)) + return 0 + check_eye(src) + return 1 + +/mob/living/silicon/ai/switch_to_camera(var/obj/machinery/camera/C) + if(!C.can_use() || !is_in_chassis()) + return 0 + + eyeobj.setLoc(C) + return 1 diff --git a/code/modules/nano/modules/alarm_monitor.dm b/code/modules/nano/modules/alarm_monitor.dm new file mode 100644 index 0000000000..f0044506c8 --- /dev/null +++ b/code/modules/nano/modules/alarm_monitor.dm @@ -0,0 +1,86 @@ +/obj/nano_module/alarm_monitor + name = "Alarm monitor" + var/list_cameras = 0 // Whether or not to list camera references. A future goal would be to merge this with the enginering/security camera console. + var/list/datum/alarm_handler/alarm_handlers // The particular list of alarm handlers this alarm monitor should present to the user. + +/obj/nano_module/alarm_monitor/ai + list_cameras = 1 + +/obj/nano_module/alarm_monitor/ai/New() + ..() + alarm_handlers = alarm_manager.all_handlers + +/obj/nano_module/alarm_monitor/borg/New() + ..() + alarm_handlers = alarm_manager.all_handlers + +/obj/nano_module/alarm_monitor/engineering/New() + ..() + alarm_handlers = list(atmosphere_alarm, fire_alarm, power_alarm) + +/obj/nano_module/alarm_monitor/security/New() + ..() + alarm_handlers = list(camera_alarm, motion_alarm) + +/obj/nano_module/alarm_monitor/proc/register(var/object, var/procName) + for(var/datum/alarm_handler/AH in alarm_handlers) + AH.register(object, procName) + +/obj/nano_module/alarm_monitor/proc/unregister(var/object) + for(var/datum/alarm_handler/AH in alarm_handlers) + AH.unregister(object) + +/obj/nano_module/alarm_monitor/proc/active_alarms() + var/list/all_alarms = new() + for(var/datum/alarm_handler/AH in alarm_handlers) + var/list/alarms = AH.alarms + all_alarms += alarms + + return all_alarms + +/obj/nano_module/alarm_monitor/Topic(href, href_list) + if(..()) return 1 + +/obj/nano_module/alarm_monitor/ai/Topic(ref, href_list) + if(..()) + return 1 + if(href_list["switchTo"]) + var/obj/machinery/camera/C = locate(href_list["switchTo"]) in cameranet.cameras + if(!C) + + return + + usr.switch_to_camera(C) + return 1 + +/obj/nano_module/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + + var/categories[0] + for(var/datum/alarm_handler/AH in alarm_handlers) + categories[++categories.len] = list("category" = AH.category, "alarms" = list()) + for(var/datum/alarm/A in AH.alarms) + var/cameras[0] + var/lost_sources[0] + + if(list_cameras) + for(var/obj/machinery/camera/C in A.cameras()) + cameras[++cameras.len] = C.nano_structure() + for(var/datum/alarm_source/AS in A.sources) + if(!AS.source) + lost_sources[++lost_sources.len] = AS.source_name + + categories[categories.len]["alarms"] += list(list( + "name" = sanitize(A.alarm_name()), + "origin_lost" = A.origin == null, + "has_cameras" = cameras.len, + "cameras" = cameras, + "lost_sources" = sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")))) + data["categories"] = categories + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) diff --git a/code/modules/nano/modules/rcon.dm b/code/modules/nano/modules/rcon.dm index 6224c56de8..abdae311d0 100644 --- a/code/modules/nano/modules/rcon.dm +++ b/code/modules/nano/modules/rcon.dm @@ -1,5 +1,5 @@ /obj/nano_module/rcon - name = "RCON interface" + name = "Power RCON" var/list/known_SMESs = null var/list/known_breakers = null diff --git a/nano/css/shared.css b/nano/css/shared.css index b81990b7a3..97b0604ad1 100644 --- a/nano/css/shared.css +++ b/nano/css/shared.css @@ -271,6 +271,12 @@ div.notice { color: #e9c183; } +.itemLabelWidest { + float: left; + width: 100%; + color: #e9c183; +} + .itemContentWide { float: left; width: 79%; diff --git a/nano/templates/alarm_monitor.tmpl b/nano/templates/alarm_monitor.tmpl new file mode 100644 index 0000000000..0089467e43 --- /dev/null +++ b/nano/templates/alarm_monitor.tmpl @@ -0,0 +1,37 @@ + + +{{for data.categories}} +

{{:value.category}}

+ {{for value.alarms :alarmValue:alarmIndex}} + {{if alarmValue.origin_lost}} + {{:alarmValue.name}} Alarm Origin Lost
+ {{else}} + {{:alarmValue.name}}
+ {{/if}} + {{if alarmValue.has_cameras || alarmValue.lost_sources != ""}} +
+ {{if alarmValue.has_cameras}} +
+ {{for alarmValue.cameras :cameraValue:cameraIndex}} + {{if cameraValue.deact}} + {{:helper.link(cameraValue.name + " (deactivated)", '', {}, 'inactive')}} + {{else}} + {{:helper.link(cameraValue.name, '', {'switchTo' : cameraValue.camera})}} + {{/if}} + {{/for}} +
+ {{/if}} + {{if alarmValue.lost_sources != ""}} +
+

Lost Alarm Sources: {{:alarmValue.lost_sources}}

+
+ {{/if}} +
+ {{/if}} + {{empty}} + --All Systems Nominal + {{/for}} +{{/for}} \ No newline at end of file