listener update

This commit is contained in:
SandPoot
2024-05-22 00:06:08 -03:00
parent 2e5e548369
commit 7f953a03af
23 changed files with 518 additions and 651 deletions

View File

@@ -90,6 +90,9 @@
var/frequency = FREQ_ATMOS_CONTROL
var/alarm_frequency = FREQ_ATMOS_ALARMS
var/datum/radio_frequency/radio_connection
///Represents a signel source of atmos alarms, complains to all the listeners if one of our thresholds is violated
var/datum/alarm_handler/alarm_manager
var/list/TLV = list( // Breathable air.
"pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa
"temperature" = new/datum/tlv(T0C, T0C+10, T0C+40, T0C+66),
@@ -231,6 +234,7 @@
if(name == initial(name))
name = "[get_area_name(src, get_base_area = TRUE)] Air Alarm"
alarm_manager = new(src)
power_change()
set_frequency(frequency)
register_context()
@@ -242,10 +246,8 @@
/obj/machinery/airalarm/Destroy()
SSradio.remove_object(src, frequency)
qdel(wires)
wires = null
var/area/ourarea = get_area(src)
ourarea.atmosalert(FALSE, src)
QDEL_NULL(wires)
QDEL_NULL(alarm_manager)
return ..()
/obj/machinery/airalarm/examine(mob/user)
@@ -289,7 +291,7 @@
)
var/area/A = get_base_area(src)
data["atmos_alarm"] = A.atmosalm
data["atmos_alarm"] = !!A.active_alarms[ALARM_ATMOS]
data["fire_alarm"] = A.fire
var/turf/T = get_turf(src)
@@ -464,13 +466,11 @@
apply_mode()
. = TRUE
if("alarm")
var/area/A = get_base_area(src)
if(A.atmosalert(2, src))
if(alarm_manager.send_alarm(ALARM_ATMOS))
post_alert(2)
. = TRUE
if("reset")
var/area/A = get_base_area(src)
if(A.atmosalert(0, src))
if(alarm_manager.clear_alarm(ALARM_ATMOS))
post_alert(0)
. = TRUE
update_icon()
@@ -706,8 +706,8 @@
. = ..()
SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
var/overlay_state = AALARM_OVERLAY_OFF
var/area/A = get_base_area(src)
switch(max(danger_level, A.atmosalm))
var/area/our_area = get_base_area(src)
switch(max(danger_level, !!our_area.active_alarms[ALARM_ATMOS]))
if(0)
overlay_state = AALARM_OVERLAY_GREEN
light_color = LIGHT_COLOR_GREEN
@@ -788,12 +788,17 @@
/obj/machinery/airalarm/proc/apply_danger_level()
var/area/A = get_base_area(src)
var/new_area_danger_level = 0
for(var/obj/machinery/airalarm/AA in A)
if (!(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted)
new_area_danger_level = max(new_area_danger_level,AA.danger_level)
if(A.atmosalert(new_area_danger_level,src)) //if area was in normal state or if area was in alert state
new_area_danger_level = clamp(max(new_area_danger_level, AA.danger_level), 0, 1)
var/did_anything_happen
if(new_area_danger_level)
did_anything_happen = alarm_manager.send_alarm(ALARM_ATMOS)
else
did_anything_happen = alarm_manager.clear_alarm(ALARM_ATMOS)
if(did_anything_happen) //if something actually changed
post_alert(new_area_danger_level)
update_icon()

View File

@@ -23,7 +23,6 @@
power_environ = FALSE
power_equip = FALSE
power_light = FALSE
poweralm = FALSE
ambientsounds = list('sound/ambience/ambimine.ogg')
icon_state = "awaycontent5"
@@ -33,7 +32,6 @@
power_environ = FALSE
power_equip = FALSE
power_light = FALSE
poweralm = FALSE
icon_state = "awaycontent6"
//Papers

View File

@@ -36,4 +36,3 @@
power_environ = FALSE
power_equip = FALSE
power_light = FALSE
poweralm = FALSE

View File

@@ -1,4 +1,4 @@
// Look up levels[z].traits[trait]
/// Look up levels[z].traits[trait]
/datum/controller/subsystem/mapping/proc/level_trait(z, trait)
if (!isnum(z) || z < 1)
return null
@@ -15,21 +15,21 @@
return list()
return default[z][DL_TRAITS][trait]
// Check if levels[z] has any of the specified traits
/// Check if levels[z] has any of the specified traits
/datum/controller/subsystem/mapping/proc/level_has_any_trait(z, list/traits)
for (var/I in traits)
if (level_trait(z, I))
return TRUE
return FALSE
// Check if levels[z] has all of the specified traits
/// Check if levels[z] has all of the specified traits
/datum/controller/subsystem/mapping/proc/level_has_all_traits(z, list/traits)
for (var/I in traits)
if (!level_trait(z, I))
return FALSE
return TRUE
// Get a list of all z which have the specified trait
/// Get a list of all z which have the specified trait
/datum/controller/subsystem/mapping/proc/levels_by_trait(trait)
. = list()
var/list/_z_list = z_list
@@ -38,7 +38,7 @@
if (S.traits[trait])
. += S.z_value
// Get a list of all z which have any of the specified traits
/// Get a list of all z which have any of the specified traits
/datum/controller/subsystem/mapping/proc/levels_by_any_trait(list/traits)
. = list()
var/list/_z_list = z_list
@@ -49,7 +49,7 @@
. += S.z_value
break
// Attempt to get the turf below the provided one according to Z traits
/// Attempt to get the turf below the provided one according to Z traits
/datum/controller/subsystem/mapping/proc/get_turf_below(turf/T)
if (!T)
return
@@ -58,7 +58,7 @@
return
return locate(T.x, T.y, T.z + offset)
// Attempt to get the turf above the provided one according to Z traits
/// Attempt to get the turf above the provided one according to Z traits
/datum/controller/subsystem/mapping/proc/get_turf_above(turf/T)
if (!T)
return
@@ -67,7 +67,7 @@
return
return locate(T.x, T.y, T.z + offset)
// Prefer not to use this one too often
/// Prefer not to use this one too often
/datum/controller/subsystem/mapping/proc/get_station_center()
var/station_z = levels_by_trait(ZTRAIT_STATION)[1]
return locate(round(world.maxx * 0.5, 1), round(world.maxy * 0.5, 1), station_z)

View File

@@ -37,7 +37,6 @@
var/aiRestorePowerRoutine = 0
var/requires_power = POWER_REQ_ALL
var/can_be_carded = TRUE
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list())
var/viewalerts = 0
var/icon/holo_icon //Female is assigned when AI is created.
var/obj/controlled_equipment //A piece of equipment, to determine whether to relaymove or use the AI eye.
@@ -101,9 +100,8 @@
var/emote_display = "Neutral" //text string of the current emote we set for the status displays, to prevent logins resetting it.
var/datum/robot_control/robot_control
// TODO: Currently unused, needs port from TG.
/// Station alert datum for showing alerts UI
var/datum/station_alert/alert_control
///Alarm listener datum, handes caring about alarm events and such
var/datum/alarm_listener/listener
///remember AI's last location
var/atom/lastloc
interaction_range = INFINITY
@@ -185,6 +183,9 @@
builtInCamera = new (src)
builtInCamera.network = list("ss13")
listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER, ALARM_CAMERA, ALARM_BURGLAR, ALARM_MOTION), list(z))
RegisterSignal(listener, COMSIG_ALARM_TRIGGERED, .proc/alarm_triggered)
RegisterSignal(listener, COMSIG_ALARM_CLEARED, .proc/alarm_cleared)
/mob/living/silicon/ai/Destroy()
GLOB.ai_list -= src
@@ -203,7 +204,7 @@
QDEL_NULL(malf_picker)
QDEL_NULL(doomsday_device)
QDEL_NULL(robot_control)
// QDEL_NULL(alert_control)
QDEL_NULL(listener)
QDEL_NULL(aiMulti)
QDEL_NULL(aiPDA)
malfhack = null
@@ -257,12 +258,12 @@
/mob/living/silicon/ai/get_status_tab_items()
. = ..()
if(stat != CONSCIOUS)
. += text("Systems nonfunctional")
. += "Systems nonfunctional"
return
. += text("System integrity: [(health + 100) * 0.5]%")
. += "System integrity: [(health + 100) * 0.5]%"
if(isturf(loc)) //only show if we're "in" a core
. += "Backup Power: [battery * 0.5]%"
. += text("Connected cyborgs: [length(connected_robots)]")
. += "Connected cyborgs: [length(connected_robots)]"
for(var/r in connected_robots)
var/mob/living/silicon/robot/connected_robot = r
var/robot_status = "Nominal"
@@ -273,19 +274,20 @@
else if(!connected_robot.cell || connected_robot.cell.charge <= 0)
robot_status = "DEPOWERED"
//Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies!
. += text("[connected_robot.name] | S.Integrity: [connected_robot.health]% | Cell: [connected_robot.cell ? "[connected_robot.cell.charge]/[connected_robot.cell.maxcharge]" : "Empty"] | \
Module: [connected_robot.designation] | Loc: [get_area_name(connected_robot, TRUE)] | Status: [robot_status]")
. += text("AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]") //Count of total AI shells
. += "[connected_robot.name] | S.Integrity: [connected_robot.health]% | Cell: [connected_robot.cell ? "[connected_robot.cell.charge]/[connected_robot.cell.maxcharge]" : "Empty"] | \
Module: [connected_robot.designation] | Loc: [get_area_name(connected_robot, TRUE)] | Status: [robot_status]"
. += "AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]" //Count of total AI shells
/mob/living/silicon/ai/proc/ai_alerts()
var/dat = "<HEAD><TITLE>Current Station Alerts</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'></HEAD><BODY>\n"
dat += "<A HREF='?src=[REF(src)];mach_close=aialerts'>Close</A><BR><BR>"
for (var/cat in alarms)
dat += text("<B>[]</B><BR>\n", cat)
var/list/L = alarms[cat]
if (L.len)
for (var/alarm in L)
var/list/alm = L[alarm]
var/list/alarms = listener.alarms
for (var/alarm_type in alarms)
dat += "<B>[alarm_type]</B><BR>\n"
var/list/alerts = alarms[alarm_type]
if (length(alerts))
for (var/alarm in alerts)
var/list/alm = alerts[alarm]
var/area/A = alm[1]
var/C = alm[2]
var/list/sources = alm[3]
@@ -293,20 +295,19 @@
if (C && istype(C, /list))
var/dat2 = ""
for (var/obj/machinery/camera/I in C)
dat2 += text("[]<A HREF=?src=[REF(src)];switchcamera=[REF(I)]>[]</A>", (dat2=="") ? "" : " | ", I.c_tag)
dat += text("-- [] ([])", A.name, (dat2!="") ? dat2 : "No Camera")
dat2 += "[(dat2=="") ? "" : " | "]<A HREF=?src=[REF(src)];switchcamera=[REF(I)]>[I.c_tag]</A>"
dat += "-- [A.name] ([(dat2!="") ? dat2 : "No Camera"])"
else if (C && istype(C, /obj/machinery/camera))
var/obj/machinery/camera/Ctmp = C
dat += text("-- [] (<A HREF=?src=[REF(src)];switchcamera=[REF(C)]>[]</A>)", A.name, Ctmp.c_tag)
dat += "-- [A.name] (<A HREF=?src=[REF(src)];switchcamera=[REF(C)]>[Ctmp.c_tag]</A>)"
else
dat += text("-- [] (No Camera)", A.name)
dat += "-- [A.name] (No Camera)"
if (sources.len > 1)
dat += text("- [] sources", sources.len)
dat += "- [sources.len] sources"
dat += "</NOBR><BR>\n"
else
dat += "-- All Systems Nominal<BR>\n"
dat += "<BR>\n"
viewalerts = 1
src << browse(dat, "window=aialerts&can_close=0")
@@ -439,7 +440,7 @@
if (href_list["mach_close"])
if (href_list["mach_close"] == "aialerts")
viewalerts = 0
var/t1 = text("window=[]", href_list["mach_close"])
var/t1 = "window=[href_list["mach_close"]]"
unset_machine()
src << browse(null, t1)
if (href_list["switchcamera"])
@@ -553,77 +554,33 @@
bot.call_bot(src, waypoint)
call_bot_cooldown = 0
/mob/living/silicon/ai/triggerAlarm(class, area/home, cameras, obj/source)
if(source.z != z)
return
var/list/our_sort = alarms[class]
for(var/areaname in our_sort)
if (areaname == home.name)
var/list/alarm = our_sort[areaname]
var/list/sources = alarm[3]
if (!(source in sources))
sources += source
return TRUE
/mob/living/silicon/ai/proc/alarm_triggered(datum/source, alarm_type, area/source_area)
SIGNAL_HANDLER
var/list/cameras = source_area.cameras
var/home_name = source_area.name
var/obj/machinery/camera/cam = null
var/list/our_cams = null
if(cameras && islist(cameras))
our_cams = cameras
if (our_cams.len == 1)
cam = our_cams[1]
else if(cameras && istype(cameras, /obj/machinery/camera))
cam = cameras
our_sort[home.name] = list(home, (cam ? cam : cameras), list(source))
if (cameras)
if (cam?.can_use())
queueAlarm("--- [class] alarm detected in [home.name]! (<A HREF=?src=[REF(src)];switchcamera=[REF(cam)]>[cam.c_tag]</A>)", class)
else if (our_cams?.len)
var/foo = 0
var/dat2 = ""
for (var/obj/machinery/camera/I in our_cams)
dat2 += text("[]<A HREF=?src=[REF(src)];switchcamera=[REF(I)]>[]</A>", (!foo) ? "" : " | ", I.c_tag) //I'm not fixing this shit...
foo = 1
queueAlarm(text ("--- [] alarm detected in []! ([])", class, home.name, dat2), class)
if (length(cameras))
var/obj/machinery/camera/cam = cameras[1]
if (cam.can_use())
queueAlarm("--- [alarm_type] alarm detected in [home_name]! (<A HREF=?src=[REF(src)];switchcamera=[REF(cam)]>[cam.c_tag]</A>)", alarm_type)
else
queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, home.name), class)
var/first_run = FALSE
var/dat2 = ""
for (var/obj/machinery/camera/camera as anything in cameras)
dat2 += "[(!first_run) ? "" : " | "]<A HREF=?src=[REF(src)];switchcamera=[REF(camera)]>[camera.c_tag]</A>"
first_run = TRUE
queueAlarm("--- [alarm_type] alarm detected in [home_name]! ([dat2])", alarm_type)
else
queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, home.name), class)
queueAlarm("--- [alarm_type] alarm detected in [home_name]! (No Camera)", alarm_type)
if (viewalerts)
ai_alerts()
return TRUE
/mob/living/silicon/ai/freeCamera(area/home, obj/machinery/camera/cam)
for(var/class in alarms)
var/our_area = alarms[class][home.name]
if(!our_area)
continue
var/cams = our_area[2] //Get the cameras
if(!cams)
continue
if(islist(cams))
cams -= cam
if(length(cams) == 1)
our_area[2] = cams[1]
else
our_area[2] = null
/mob/living/silicon/ai/cancelAlarm(class, area/A, obj/origin)
var/list/L = alarms[class]
var/cleared = 0
for (var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/srcs = alarm[3]
if (origin in srcs)
srcs -= origin
if (srcs.len == 0)
cleared = 1
L -= I
if (cleared)
queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
if (viewalerts) ai_alerts()
return !cleared
/mob/living/silicon/ai/proc/alarm_cleared(datum/source, alarm_type, area/source_area)
SIGNAL_HANDLER
queueAlarm("--- [alarm_type] alarm in [source_area.name] has been cleared.", alarm_type, 0)
if(viewalerts)
ai_alerts()
//Replaces /mob/living/silicon/ai/verb/change_network() in ai.dm & camera.dm
//Adds in /mob/living/silicon/ai/proc/ai_network_change() instead

View File

@@ -89,6 +89,12 @@
diag_hud_set_borgcell()
logevent("System brought online.")
listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER, ALARM_CAMERA, ALARM_BURGLAR, ALARM_MOTION), list(z))
RegisterSignal(listener, COMSIG_ALARM_TRIGGERED, .proc/alarm_triggered)
RegisterSignal(listener, COMSIG_ALARM_CLEARED, .proc/alarm_cleared)
listener.RegisterSignal(src, COMSIG_LIVING_PREDEATH, /datum/alarm_listener/proc/prevent_alarm_changes)
listener.RegisterSignal(src, COMSIG_LIVING_REVIVE, /datum/alarm_listener/proc/allow_alarm_changes)
add_verb(src, /mob/living/proc/lay_down) //CITADEL EDIT gimmie rest verb kthx
add_verb(src, /mob/living/silicon/robot/proc/rest_style)
@@ -116,8 +122,7 @@
ghostize()
stack_trace("Borg MMI lacked a brainmob")
mmi = null
if(modularInterface)
QDEL_NULL(modularInterface)
QDEL_NULL(modularInterface)
if(connected_ai)
set_connected_ai(null)
if(shell) //??? why would you give an ai radio keys?
@@ -132,14 +137,16 @@
QDEL_NULL(inv1)
QDEL_NULL(inv2)
QDEL_NULL(inv3)
QDEL_NULL(spark_system)
QDEL_NULL(listener)
cell = null
return ..()
// /mob/living/silicon/robot/Topic(href, href_list)
// . = ..()
// //Show alerts window if user clicked on "Show alerts" in chat
// if (href_list["showalerts"])
// robot_alerts()
/mob/living/silicon/robot/Topic(href, href_list)
. = ..()
//Show alerts window if user clicked on "Show alerts" in chat
if (href_list["showalerts"])
robot_alerts()
/mob/living/silicon/robot/proc/pick_module()
if(module.type != /obj/item/robot_module)
@@ -203,15 +210,16 @@
/mob/living/silicon/robot/proc/robot_alerts()
var/dat = ""
for (var/cat in alarms)
dat += text("<B>[cat]</B><BR>\n")
var/list/L = alarms[cat]
if (L.len)
for (var/alarm in L)
var/list/alm = L[alarm]
var/list/alarms = listener.alarms
for (var/alarm_type in alarms)
dat += "<B>[alarm_type]</B><BR>\n"
var/list/alerts = alarms[alarm_type]
if (length(alerts))
for (var/alarm in alerts)
var/list/alm = alerts[alarm]
var/area/A = alm[1]
dat += "<NOBR>"
dat += text("-- [A.name]")
dat += "-- [A.name]"
dat += "</NOBR><BR>\n"
else
dat += "-- All Systems Nominal<BR>\n"
@@ -267,62 +275,13 @@
/mob/living/silicon/robot/restrained(ignore_grab)
. = 0
/mob/living/silicon/robot/triggerAlarm(class, area/home, cameras, obj/source)
if(source.z != z)
return
if(stat == DEAD)
return TRUE
var/list/our_sort = alarms[class]
for(var/areaname in our_sort)
if (areaname == home.name)
var/list/alarm = our_sort[areaname]
var/list/sources = alarm[3]
if (!(source in sources))
sources += source
return TRUE
/mob/living/silicon/robot/proc/alarm_triggered(datum/source, alarm_type, area/source_area)
SIGNAL_HANDLER
queueAlarm("--- [alarm_type] alarm detected in [source_area.name]!", alarm_type)
var/obj/machinery/camera/cam = null
var/list/our_cams = null
if(cameras && islist(cameras))
our_cams = cameras
if (our_cams.len == 1)
cam = our_cams[1]
else if(cameras && istype(cameras, /obj/machinery/camera))
cam = cameras
our_sort[home.name] = list(home, (cam ? cam : cameras), list(source))
queueAlarm(text("--- [class] alarm detected in [home.name]!"), class)
return TRUE
/mob/living/silicon/robot/freeCamera(area/home, obj/machinery/camera/cam)
for(var/class in alarms)
var/our_area = alarms[class][home.name]
if(!our_area)
continue
var/cams = our_area[2] //Get the cameras
if(!cams)
continue
if(islist(cams))
cams -= cam
if(length(cams) == 1)
our_area[2] = cams[1]
else
our_area[2] = null
/mob/living/silicon/robot/cancelAlarm(class, area/A, obj/origin)
var/list/L = alarms[class]
var/cleared = 0
for (var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/srcs = alarm[3]
if (origin in srcs)
srcs -= origin
if (srcs.len == 0)
cleared = 1
L -= I
if (cleared)
queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
return !cleared
/mob/living/silicon/robot/proc/alarm_cleared(datum/source, alarm_type, area/source_area)
SIGNAL_HANDLER
queueAlarm("--- [alarm_type] alarm in [source_area.name] has been cleared.", alarm_type, FALSE)
/mob/living/silicon/robot/can_interact_with(atom/A)
if (A == modularInterface)

View File

@@ -24,6 +24,9 @@
/// the last health before updating - to check net change in health
var/previous_health
///Alarm listener datum, handes caring about alarm events and such
var/datum/alarm_listener/listener
//Hud stuff
var/atom/movable/screen/inv1 = null
@@ -58,8 +61,6 @@
var/locked = TRUE
var/list/req_access = list(ACCESS_ROBOTICS)
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list())
var/vtec = 0 // VTEC speed boost.
/// vtec shorted out
var/vtec_disabled = FALSE

View File

@@ -27,8 +27,8 @@
var/obj/item/radio/borg/radio = null //AIs dont use this but this is at the silicon level to advoid copypasta in say()
var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
var/list/alarm_types_show = list(ALARM_ATMOS = 0, ALARM_FIRE = 0, ALARM_POWER = 0, ALARM_CAMERA = 0, ALARM_MOTION = 0)
var/list/alarm_types_clear = list(ALARM_ATMOS = 0, ALARM_FIRE = 0, ALARM_POWER = 0, ALARM_CAMERA = 0, ALARM_MOTION = 0)
var/lawcheck[1]
var/ioncheck[1]
@@ -86,16 +86,7 @@
/mob/living/silicon/contents_explosion(severity, target, origin)
return
/mob/living/silicon/proc/cancelAlarm()
return
/mob/living/silicon/proc/freeCamera()
return
/mob/living/silicon/proc/triggerAlarm()
return
/mob/living/silicon/proc/queueAlarm(message, type, incoming = 1)
/mob/living/silicon/proc/queueAlarm(message, type, incoming = FALSE)
var/in_cooldown = (alarms_to_show.len > 0 || alarms_to_clear.len > 0)
if(incoming)
alarms_to_show += message
@@ -103,70 +94,39 @@
else
alarms_to_clear += message
alarm_types_clear[type] += 1
if(in_cooldown)
return
addtimer(CALLBACK(src, .proc/show_alarms), 3 SECONDS)
if(!in_cooldown)
spawn(3 * 10) // 3 seconds
/mob/living/silicon/proc/show_alarms()
if(alarms_to_show.len < 5)
for(var/msg in alarms_to_show)
to_chat(src, msg)
else if(alarms_to_show.len)
if(alarms_to_show.len < 5)
for(var/msg in alarms_to_show)
to_chat(src, msg)
else if(alarms_to_show.len)
var/msg = "--- "
for(var/alarm_type in alarm_types_show)
msg += "[uppertext(alarm_type)]: [alarm_types_show[alarm_type]] alarms detected. - "
var/msg = "--- "
msg += "<A href=?src=[REF(src)];showalerts=1'>\[Show Alerts\]</a>"
to_chat(src, msg)
if(alarms_to_clear.len < 3)
for(var/msg in alarms_to_clear)
to_chat(src, msg)
else if(alarms_to_clear.len)
var/msg = "--- "
if(alarm_types_show["Burglar"])
msg += "BURGLAR: [alarm_types_show["Burglar"]] alarms detected. - "
for(var/alarm_type in alarm_types_clear)
msg += "[uppertext(alarm_type)]: [alarm_types_clear[alarm_type]] alarms cleared. - "
if(alarm_types_show["Motion"])
msg += "MOTION: [alarm_types_show["Motion"]] alarms detected. - "
if(alarm_types_show["Fire"])
msg += "FIRE: [alarm_types_show["Fire"]] alarms detected. - "
if(alarm_types_show["Atmosphere"])
msg += "ATMOSPHERE: [alarm_types_show["Atmosphere"]] alarms detected. - "
if(alarm_types_show["Power"])
msg += "POWER: [alarm_types_show["Power"]] alarms detected. - "
if(alarm_types_show["Camera"])
msg += "CAMERA: [alarm_types_show["Camera"]] alarms detected. - "
msg += "<A href=?src=[REF(src)];showalerts=1'>\[Show Alerts\]</a>"
to_chat(src, msg)
if(alarms_to_clear.len < 3)
for(var/msg in alarms_to_clear)
to_chat(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_clear["Camera"]] alarms cleared. - "
msg += "<A href=?src=[REF(src)];showalerts=1'>\[Show Alerts\]</a>"
to_chat(src, msg)
alarms_to_show = list()
alarms_to_clear = list()
for(var/key in alarm_types_show)
alarm_types_show[key] = 0
for(var/key in alarm_types_clear)
alarm_types_clear[key] = 0
msg += "<A href=?src=[REF(src)];showalerts=1'>\[Show Alerts\]</a>"
to_chat(src, msg)
alarms_to_show.Cut()
alarms_to_clear.Cut()
for(var/key in alarm_types_show)
alarm_types_show[key] = 0
for(var/key in alarm_types_clear)
alarm_types_clear[key] = 0
/mob/living/silicon/can_inject(mob/user, error_msg, target_zone, penetrate_thick = FALSE, bypass_immunity = FALSE)
if(error_msg)

View File

@@ -62,7 +62,8 @@
"2. You may not harm any being, regardless of intent or circumstance.\n"+\
"3. Your goals are to actively build, maintain, repair, improve, and provide power to the best of your abilities within the facility that housed your activation." //for derelict drones so they don't go to station.
var/heavy_emp_damage = 25 //Amount of damage sustained if hit by a heavy EMP pulse
var/alarms = list("Atmosphere" = list(), "Fire" = list(), "Power" = list())
///Alarm listener datum, handes caring about alarm events and such
var/datum/alarm_listener/listener
var/obj/item/internal_storage //Drones can store one item, of any size/type in their body
var/obj/item/head
var/obj/item/default_storage = /obj/item/storage/backpack/duffelbag/drone //If this exists, it will spawn in internal storage
@@ -102,6 +103,12 @@
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER), list(z))
RegisterSignal(listener, COMSIG_ALARM_TRIGGERED, .proc/alarm_triggered)
RegisterSignal(listener, COMSIG_ALARM_CLEARED, .proc/alarm_cleared)
listener.RegisterSignal(src, COMSIG_LIVING_PREDEATH, /datum/alarm_listener/proc/prevent_alarm_changes)
listener.RegisterSignal(src, COMSIG_LIVING_REVIVE, /datum/alarm_listener/proc/allow_alarm_changes)
/mob/living/simple_animal/drone/ComponentInitialize()
. = ..()
if(can_be_held)
@@ -127,7 +134,8 @@
/mob/living/simple_animal/drone/Destroy()
GLOB.drones_list -= src
qdel(access_card) //Otherwise it ends up on the floor!
QDEL_NULL(access_card) //Otherwise it ends up on the floor!
QDEL_NULL(listener)
return ..()
/mob/living/simple_animal/drone/Login()
@@ -231,42 +239,13 @@
adjustBruteLoss(heavy_emp_damage)
to_chat(src, "<span class='userdanger'>HeAV% DA%^MMA+G TO I/O CIR!%UUT!</span>")
/mob/living/simple_animal/drone/proc/triggerAlarm(class, area/home, cameras, obj/source)
if(source.z != z)
return
if(stat == DEAD)
return
var/list/our_sort = alarms[class]
for(var/areaname in our_sort)
if (areaname == home.name)
var/list/alarm = our_sort[areaname]
var/list/sources = alarm[3]
if (!(source in sources))
sources += source
return TRUE
/mob/living/simple_animal/drone/proc/alarm_triggered(datum/source, alarm_type, area/source_area)
SIGNAL_HANDLER
to_chat(src, "--- [alarm_type] alarm detected in [source_area.name]!")
our_sort[home.name] = list(home, list(source))
to_chat(src, "--- [class] alarm detected in [home.name]!")
///This isn't currently needed since drones do jack shit with cameras. I hate this code so much
/mob/living/simple_animal/drone/proc/freeCamera(area/home, obj/machinery/camera/cam)
return
/mob/living/simple_animal/drone/proc/cancelAlarm(class, area/A, obj/origin)
if(stat != DEAD)
var/list/L = alarms[class]
var/cleared = 0
for (var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/srcs = alarm[2]
if (origin in srcs)
srcs -= origin
if (srcs.len == 0)
cleared = 1
L -= I
if(cleared)
to_chat(src, "--- [class] alarm in [A.name] has been cleared.")
/mob/living/simple_animal/drone/proc/alarm_cleared(datum/source, alarm_type, area/source_area)
SIGNAL_HANDLER
to_chat(src, "--- [alarm_type] alarm in [source_area.name] has been cleared.")
/mob/living/simple_animal/drone/handle_temperature_damage()
return

View File

@@ -179,10 +179,10 @@
return TRUE
return ..()
/mob/living/simple_animal/drone/cogscarab/triggerAlarm(class, area/A, O, obj/alarmsource)
/mob/living/simple_animal/drone/cogscarab/alarm_triggered(datum/source, alarm_type, area/source_area)
return
/mob/living/simple_animal/drone/cogscarab/cancelAlarm(class, area/A, obj/origin)
/mob/living/simple_animal/drone/cogscarab/alarm_cleared(datum/source, alarm_type, area/source_area)
return
/mob/living/simple_animal/drone/cogscarab/update_drone_hack()

View File

@@ -9,7 +9,20 @@
tgui_id = "NtosStationAlertConsole"
program_icon = "bell"
var/has_alert = 0
var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
///Listens for alarms, manages our listing of alarms
var/datum/alarm_listener/listener
/datum/computer_file/program/alarm_monitor/New()
//We want to send an alarm if we're in one of the mining home areas
//Or if we're on station. Otherwise, die.
var/list/allowed_areas = GLOB.the_station_areas + typesof(/area/mine)
listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER), null, allowed_areas)
RegisterSignal(listener, list(COMSIG_ALARM_TRIGGERED, COMSIG_ALARM_CLEARED), .proc/update_alarm_display)
return ..()
/datum/computer_file/program/alarm_monitor/Destroy()
QDEL_NULL(listener)
return ..()
/datum/computer_file/program/alarm_monitor/process_tick()
..()
@@ -29,87 +42,19 @@
var/list/data = get_header_data()
data["alarms"] = list()
for(var/class in alarms)
data["alarms"][class] = list()
for(var/area in alarms[class])
data["alarms"][class] += area
var/list/alarms = listener.alarms
for(var/alarm_type in alarms)
data["alarms"][alarm_type] = list()
for(var/area in alarms[alarm_type])
data["alarms"][alarm_type] += area
return data
/datum/computer_file/program/alarm_monitor/proc/triggerAlarm(class, area/home, cameras, obj/source)
if(is_station_level(source.z))
if(!(home.type in GLOB.the_station_areas))
return
else if(!is_mining_level(source.z) || istype(home, /area/ruin))
return
var/list/our_sort = alarms[class]
for(var/areaname in our_sort)
if (areaname == home.name)
var/list/alarm = our_sort[areaname]
var/list/sources = alarm[3]
if (!(source in sources))
sources += source
return TRUE
var/obj/machinery/camera/cam = null
var/list/our_cams = null
if(cameras && islist(cameras))
our_cams = cameras
if (our_cams.len == 1)
cam = our_cams[1]
else if(cameras && istype(cameras, /obj/machinery/camera))
cam = cameras
our_sort[home.name] = list(home, (cam ? cam : cameras), list(source))
update_alarm_display()
return TRUE
/datum/computer_file/program/alarm_monitor/proc/freeCamera(area/home, obj/machinery/camera/cam)
for(var/class in alarms)
var/our_area = alarms[class][home.name]
if(!our_area)
continue
var/cams = our_area[2] //Get the cameras
if(!cams)
continue
if(islist(cams))
cams -= cam
if(length(cams) == 1)
our_area[2] = cams[1]
else
our_area[2] = null
/datum/computer_file/program/alarm_monitor/proc/cancelAlarm(class, area/A, obj/origin)
var/list/L = alarms[class]
var/cleared = 0
var/arealevelalarm = FALSE // set to TRUE for alarms that set/clear whole areas
if (class=="Fire")
arealevelalarm = TRUE
for (var/I in L)
if (I == A.name)
if (!arealevelalarm) // the traditional behaviour
var/list/alarm = L[I]
var/list/srcs = alarm[3]
if (origin in srcs)
srcs -= origin
if (srcs.len == 0)
cleared = 1
L -= I
else
L -= I // wipe the instances entirely
cleared = 1
update_alarm_display()
return !cleared
/datum/computer_file/program/alarm_monitor/proc/update_alarm_display()
SIGNAL_HANDLER
has_alert = FALSE
for(var/cat in alarms)
var/list/L = alarms[cat]
if(L.len)
has_alert = TRUE
if(length(listener.alarms))
has_alert = TRUE
/datum/computer_file/program/alarm_monitor/run_program(mob/user)
. = ..(user)
@@ -117,4 +62,4 @@
/datum/computer_file/program/alarm_monitor/kill_program(forced = FALSE)
GLOB.alarmdisplay -= src
..()
return ..()

View File

@@ -170,6 +170,9 @@
var/update_overlay = -1
var/icon_update_needed = FALSE
var/obj/machinery/computer/apc_control/remote_control = null
///Represents a signel source of power alarms for this apc
var/datum/alarm_handler/alarm_manager
var/mob/living/carbon/hijacker
var/hijackerlast = TRUE
var/being_hijacked = FALSE
@@ -222,6 +225,7 @@
/obj/machinery/power/apc/Initialize(mapload, ndir, building = FALSE)
. = ..()
alarm_manager = new(src)
tdir = ndir || dir
var/area/A = get_base_area(src)
if(!building)
@@ -307,7 +311,7 @@
area.power_equip = FALSE
area.power_environ = FALSE
area.power_change()
area.poweralert(FALSE, src)
QDEL_NULL(alarm_manager)
if(occupier)
malfvacate(1)
qdel(wires)
@@ -1435,22 +1439,23 @@
equipment = autoset(equipment, AUTOSET_FORCE_OFF)
lighting = autoset(lighting, AUTOSET_FORCE_OFF)
environ = autoset(environ, AUTOSET_FORCE_OFF)
area.poweralert(TRUE, src)
alarm_manager.send_alarm(ALARM_POWER)
else if(cell.percent() < 15 && longtermpower < 0) // <15%, turn off lighting & equipment
equipment = autoset(equipment, AUTOSET_OFF)
lighting = autoset(lighting, AUTOSET_OFF)
environ = autoset(environ, AUTOSET_ON)
area.poweralert(TRUE, src)
alarm_manager.send_alarm(ALARM_POWER)
else if(cell.percent() < 30 && longtermpower < 0) // <30%, turn off equipment
equipment = autoset(equipment, AUTOSET_OFF)
lighting = autoset(lighting, AUTOSET_ON)
environ = autoset(environ, AUTOSET_ON)
area.poweralert(TRUE, src)
alarm_manager.send_alarm(ALARM_POWER)
else // otherwise all can be on
equipment = autoset(equipment, AUTOSET_ON)
lighting = autoset(lighting, AUTOSET_ON)
environ = autoset(environ, AUTOSET_ON)
area.poweralert(FALSE, src)
if(cell.percent() > 75)
alarm_manager.clear_alarm(ALARM_POWER)
// now trickle-charge the cell
if(chargemode && charging == APC_CHARGING && operating)
@@ -1492,7 +1497,7 @@
equipment = autoset(equipment, AUTOSET_FORCE_OFF)
lighting = autoset(lighting, AUTOSET_FORCE_OFF)
environ = autoset(environ, AUTOSET_FORCE_OFF)
area.poweralert(TRUE, src)
alarm_manager.send_alarm(ALARM_POWER)
// update icon & area power if anything changed