Overhauls and Refactors Alarms

This commit is contained in:
Fox McCloud
2020-07-01 17:41:47 -04:00
parent 0d7d639a0d
commit f13ae9e167
46 changed files with 982 additions and 783 deletions

View File

@@ -47768,7 +47768,7 @@
pixel_y = 3
},
/obj/item/circuitboard/powermonitor,
/obj/item/circuitboard/stationalert_all{
/obj/item/circuitboard/stationalert{
pixel_x = 3;
pixel_y = -3
},

View File

@@ -31415,7 +31415,7 @@
pixel_x = -2;
pixel_y = 2
},
/obj/item/circuitboard/stationalert_all{
/obj/item/circuitboard/stationalert{
pixel_x = 1;
pixel_y = -1
},

View File

@@ -36029,7 +36029,7 @@
},
/area/bridge)
"bnW" = (
/obj/machinery/computer/station_alert/all,
/obj/machinery/computer/station_alert,
/turf/simulated/floor/plasteel{
dir = 0;
icon_state = "yellow"
@@ -73537,7 +73537,7 @@
pixel_x = -2;
pixel_y = 2
},
/obj/item/circuitboard/stationalert_all{
/obj/item/circuitboard/stationalert{
pixel_x = 1;
pixel_y = -1
},
@@ -76805,7 +76805,7 @@
pixel_x = 32;
pixel_y = 0
},
/obj/machinery/computer/station_alert/all,
/obj/machinery/computer/station_alert,
/obj/structure/cable/yellow{
d1 = 4;
d2 = 8;

View File

@@ -31,6 +31,24 @@
areas |= T.loc
return areas
/proc/get_open_turf_in_dir(atom/center, dir)
var/turf/T = get_ranged_target_turf(center, dir, 1)
if(T && !T.density)
return T
/proc/get_adjacent_open_turfs(atom/center)
. = list(get_open_turf_in_dir(center, NORTH),
get_open_turf_in_dir(center, SOUTH),
get_open_turf_in_dir(center, EAST),
get_open_turf_in_dir(center, WEST))
listclearnulls(.)
/proc/get_adjacent_open_areas(atom/center)
. = list()
var/list/adjacent_turfs = get_adjacent_open_turfs(center)
for(var/I in adjacent_turfs)
. |= get_area(I)
// Like view but bypasses luminosity check
/proc/hear(var/range, var/atom/source)

View File

@@ -672,9 +672,6 @@ proc/dd_sortedObjectList(list/incoming)
/obj/machinery/camera/dd_SortValue()
return "[c_tag]"
/datum/alarm/dd_SortValue()
return "[sanitize(last_name)]"
//Picks from the list, with some safeties, and returns the "default" arg if it fails
#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default)

View File

@@ -9,6 +9,7 @@ GLOBAL_LIST_INIT(mechas_list, list()) //list of all mechs. Used by hostile mo
GLOBAL_LIST_INIT(spacepods_list, list()) //list of all space pods. Used by hostile mobs target tracking.
GLOBAL_LIST_INIT(joblist, list()) //list of all jobstypes, minus borg and AI
GLOBAL_LIST_INIT(airlocks, list()) //list of all airlocks
GLOBAL_LIST_EMPTY(alarmdisplay) //list of all machines or programs that can display station alerts
GLOBAL_LIST_INIT(singularities, list()) //list of all singularities
GLOBAL_LIST_INIT(janitorial_equipment, list()) //list of janitorial equipment
GLOBAL_LIST_INIT(crafting_recipes, list()) //list of all crafting recipes
@@ -16,7 +17,7 @@ GLOBAL_LIST_INIT(prisoncomputer_list, list())
GLOBAL_LIST_INIT(celltimers_list, list()) // list of all cell timers
GLOBAL_LIST_INIT(cell_logs, list())
GLOBAL_LIST_INIT(navigation_computers, list())
GLOBAL_LIST_INIT(zombie_infection_list, list())
GLOBAL_LIST_INIT(zombie_infection_list, list())
GLOBAL_LIST_INIT(all_areas, list())
GLOBAL_LIST_INIT(machines, list())
@@ -48,7 +49,7 @@ GLOBAL_LIST_EMPTY(ladders)
GLOBAL_LIST_INIT(active_diseases, list()) //List of Active disease in all mobs; purely for quick referencing.
GLOBAL_LIST_EMPTY(mob_spawners) // All mob_spawn objects
GLOBAL_LIST_EMPTY(alert_consoles) // Station alert consoles, /obj/machinery/computer/station_alert
GLOBAL_LIST_EMPTY(explosive_walls)
GLOBAL_LIST_EMPTY(engine_beacon_list)

View File

@@ -64,7 +64,7 @@
/obj/screen/ai/alerts/Click()
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
AI.subsystem_alarm_monitor()
AI.ai_alerts()
/obj/screen/ai/announcement
name = "Make Announcement"

View File

@@ -1,31 +0,0 @@
SUBSYSTEM_DEF(alarms)
name = "Alarms"
init_order = INIT_ORDER_ALARMS // 2
offline_implications = "Alarms (Power, camera, fire, etc) will no longer be checked. No immediate action is needed."
var/datum/alarm_handler/atmosphere/atmosphere_alarm = new()
var/datum/alarm_handler/burglar/burglar_alarm = new()
var/datum/alarm_handler/camera/camera_alarm = new()
var/datum/alarm_handler/fire/fire_alarm = new()
var/datum/alarm_handler/motion/motion_alarm = new()
var/datum/alarm_handler/power/power_alarm = new()
var/list/datum/alarm/all_handlers
/datum/controller/subsystem/alarms/Initialize(start_timeofday)
all_handlers = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
return ..()
/datum/controller/subsystem/alarms/fire()
for(var/datum/alarm_handler/AH in all_handlers)
AH.process()
/datum/controller/subsystem/alarms/proc/active_alarms()
var/list/all_alarms = new ()
for(var/datum/alarm_handler/AH in all_handlers)
var/list/alarms = AH.alarms
all_alarms += alarms
return all_alarms
/datum/controller/subsystem/alarms/proc/number_of_active_alarms()
var/list/alarms = active_alarms()
return alarms.len

View File

@@ -20,7 +20,7 @@
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
/client/proc/debug_controller(controller in list("failsafe", "Master", "Ticker", "Air", "Jobs", "Sun", "Radio", "Configuration", "pAI",
"Cameras", "Garbage", "Event", "Alarm", "Nano", "Vote", "Fires",
"Cameras", "Garbage", "Event", "Nano", "Vote", "Fires",
"Mob", "NPC Pool", "Shuttle", "Timer", "Weather", "Space", "Mob Hunt Server","Input"))
set category = "Debug"
set name = "Debug Controller"
@@ -64,9 +64,6 @@
if("Event")
debug_variables(SSevents)
feedback_add_details("admin_verb","DEvent")
if("Alarm")
debug_variables(SSalarms)
feedback_add_details("admin_verb", "DAlarm")
if("Nano")
debug_variables(SSnanoui)
feedback_add_details("admin_verb","DNano")

View File

@@ -79,10 +79,10 @@ GLOBAL_LIST_EMPTY(ghostteleportlocs)
/area/space/atmosalert()
return
/area/space/fire_alert()
/area/space/firealert(obj/source)
return
/area/space/fire_reset()
/area/space/firereset(obj/source)
return
/area/space/readyalert()

View File

@@ -57,6 +57,11 @@
var/list/ambientsounds = GENERIC_SOUNDS
var/list/firedoors
var/list/cameras
var/list/firealarms
var/firedoors_last_closed_on = 0
var/fast_despawn = FALSE
var/can_get_auto_cryod = TRUE
var/hide_attacklogs = FALSE // For areas such as thunderdome, lavaland syndiebase, etc which generate a lot of spammy attacklogs. Reduces log priority.
@@ -125,35 +130,6 @@
cameras += C
return cameras
/area/proc/atmosalert(danger_level, var/alarm_source, var/force = FALSE)
if(report_alerts)
if(danger_level == ATMOS_ALARM_NONE)
SSalarms.atmosphere_alarm.clearAlarm(src, alarm_source)
else
SSalarms.atmosphere_alarm.triggerAlarm(src, alarm_source, severity = danger_level)
//Check all the alarms before lowering atmosalm. Raising is perfectly fine. If force = 1 we don't care.
for(var/obj/machinery/alarm/AA in src)
if(!(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted && AA.report_danger_level && !force)
danger_level = max(danger_level, AA.danger_level)
if(danger_level != atmosalm)
if(danger_level < ATMOS_ALARM_WARNING && atmosalm >= ATMOS_ALARM_WARNING)
//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()
else if(danger_level >= ATMOS_ALARM_DANGER && atmosalm < ATMOS_ALARM_DANGER)
air_doors_close()
atmosalm = danger_level
for(var/obj/machinery/alarm/AA in src)
AA.update_icon()
GLOB.air_alarm_repository.update_cache(src)
return 1
GLOB.air_alarm_repository.update_cache(src)
return 0
/area/proc/air_doors_close()
if(!air_doors_activated)
air_doors_activated = TRUE
@@ -179,44 +155,170 @@
D.open()
/area/proc/fire_alert()
if(!fire)
fire = 1 //used for firedoor checks
updateicon()
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
air_doors_close()
/area/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/area/proc/fire_reset()
if(fire)
fire = 0 //used for firedoor checks
updateicon()
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
air_doors_open()
/**
* Generate a power alert for this area
*
* Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
*/
/area/proc/poweralert(state, obj/source)
if(state != poweralm)
poweralm = state
if(istype(source)) //Only report power alarms on the z-level where the source is located.
for(var/item in GLOB.silicon_mob_list)
var/mob/living/silicon/aiPlayer = item
if(state == 1)
aiPlayer.cancelAlarm("Power", src, source)
else
aiPlayer.triggerAlarm("Power", src, cameras, source)
return
for(var/item in GLOB.alert_consoles)
var/obj/machinery/computer/station_alert/a = item
if(state == 1)
a.cancelAlarm("Power", src, source)
else
a.triggerAlarm("Power", src, cameras, source)
/area/proc/burglaralert(var/obj/trigger)
if(always_unpowered == 1) //no burglar alarms in space/asteroid
/* for(var/item in GLOB.alarmdisplay) //TO-DO:TGUI--Uncomment Modular computers
var/datum/computer_file/program/alarm_monitor/p = item
if(state == 1)
p.cancelAlarm("Power", src, source)
else
p.triggerAlarm("Power", src, cameras, source) */
/**
* Generate an atmospheric alert for this area
*
* Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
*/
/area/proc/atmosalert(danger_level, obj/source)
if(danger_level != atmosalm)
if (danger_level==2)
for(var/item in GLOB.silicon_mob_list)
var/mob/living/silicon/aiPlayer = item
aiPlayer.triggerAlarm("Atmosphere", src, cameras, source)
for(var/item in GLOB.alert_consoles)
var/obj/machinery/computer/station_alert/a = item
a.triggerAlarm("Atmosphere", src, cameras, source)
/* for(var/item in GLOB.alarmdisplay) //TO-DO:TGUI--Uncomment Modular computers
var/datum/computer_file/program/alarm_monitor/p = item
p.triggerAlarm("Atmosphere", src, cameras, source) */
else if(src.atmosalm == 2)
for(var/item in GLOB.silicon_mob_list)
var/mob/living/silicon/aiPlayer = item
aiPlayer.cancelAlarm("Atmosphere", src, source)
for(var/item in GLOB.alert_consoles)
var/obj/machinery/computer/station_alert/a = item
a.cancelAlarm("Atmosphere", src, source)
/* for(var/item in GLOB.alarmdisplay) //TO-DO:TGUI--Uncomment Modular computers
var/datum/computer_file/program/alarm_monitor/p = item
p.cancelAlarm("Atmosphere", src, source) */
src.atmosalm = danger_level
return 1
return 0
/**
* Try to close all the firedoors in the area
*/
/area/proc/ModifyFiredoors(opening)
if(firedoors)
firedoors_last_closed_on = world.time
for(var/FD in firedoors)
var/obj/machinery/door/firedoor/D = FD
var/cont = !D.welded
if(cont && opening) //don't open if adjacent area is on fire
for(var/I in D.affecting_areas)
var/area/A = I
if(A.fire)
cont = FALSE
break
if(cont && D.is_operational())
if(D.operating)
D.nextstate = opening ? FD_OPEN : FD_CLOSED
else if(!(D.density ^ opening))
INVOKE_ASYNC(D, (opening ? /obj/machinery/door/firedoor.proc/open : /obj/machinery/door/firedoor.proc/close))
/**
* Generate a firealarm alert for this area
*
* Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
*
* Also starts the area processing on SSobj
*/
/area/proc/firealert(obj/source)
if(always_unpowered == 1) //no fire alarms in space/asteroid
return
//Trigger alarm effect
set_fire_alarm_effect()
if(!fire)
set_fire_alarm_effect()
ModifyFiredoors(FALSE)
for(var/item in firealarms)
var/obj/machinery/firealarm/F = item
F.update_icon()
//Lockdown airlocks
for(var/obj/machinery/door/airlock/A in src)
spawn(0)
A.close()
if(A.density)
A.lock()
for(var/item in GLOB.alert_consoles)
var/obj/machinery/computer/station_alert/a = item
a.triggerAlarm("Fire", src, cameras, source)
for(var/item in GLOB.silicon_mob_list)
var/mob/living/silicon/aiPlayer = item
aiPlayer.triggerAlarm("Fire", src, cameras, source)
/* for(var/item in GLOB.alarmdisplay) //TO-DO:TGUI--Uncomment Modular computers
var/datum/computer_file/program/alarm_monitor/p = item
p.triggerAlarm("Fire", src, cameras, source) */
SSalarms.burglar_alarm.triggerAlarm(src, trigger)
spawn(600)
SSalarms.burglar_alarm.clearAlarm(src, trigger)
START_PROCESSING(SSobj, src)
/area/proc/set_fire_alarm_effect()
fire = 1
updateicon()
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/**
* Reset the firealarm alert for this area
*
* resets the alert sent to all ai players, alert consoles, drones and alarm monitor programs
* in the world
*
* Also cycles the icons of all firealarms and deregisters the area from processing on SSOBJ
*/
/area/proc/firereset(obj/source)
if(fire)
unset_fire_alarm_effects()
ModifyFiredoors(TRUE)
for(var/item in firealarms)
var/obj/machinery/firealarm/F = item
F.update_icon()
for(var/item in GLOB.silicon_mob_list)
var/mob/living/silicon/aiPlayer = item
aiPlayer.cancelAlarm("Fire", src, source)
for(var/item in GLOB.alert_consoles)
var/obj/machinery/computer/station_alert/a = item
a.cancelAlarm("Fire", src, source)
/* for(var/item in GLOB.alarmdisplay) //TO-DO:TGUI--Uncomment Modular computers
var/datum/computer_file/program/alarm_monitor/p = item
p.cancelAlarm("Fire", src, source) */
STOP_PROCESSING(SSobj, src)
/**
* If 100 ticks has elapsed, toggle all the firedoors closed again
*/
/area/process()
if(firedoors_last_closed_on + 100 < world.time) //every 10 seconds
ModifyFiredoors(FALSE)
/**
* Close and lock a door passed into this proc
*
* Does this need to exist on area? probably not
*/
/area/proc/close_and_lock_door(obj/machinery/door/DOOR)
set waitfor = FALSE
DOOR.close()
if(DOOR.density)
DOOR.lock()
/area/proc/readyalert()
if(!eject)
@@ -240,13 +342,64 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
updateicon()
/**
* Raise a burglar alert for this area
*
* Close and locks all doors in the area and alerts silicon mobs of a break in
*
* Alarm auto resets after 600 ticks
*/
/area/proc/burglaralert(obj/trigger)
if(always_unpowered) //no burglar alarms in space/asteroid
return
//Trigger alarm effect
set_fire_alarm_effect()
//Lockdown airlocks
for(var/obj/machinery/door/DOOR in src)
close_and_lock_door(DOOR)
for(var/i in GLOB.silicon_mob_list)
var/mob/living/silicon/SILICON = i
if(SILICON.triggerAlarm("Burglar", src, cameras, trigger))
//Cancel silicon alert after 1 minute
addtimer(CALLBACK(SILICON, /mob/living/silicon.proc/cancelAlarm,"Burglar",src,trigger), 600)
/**
* Trigger the fire alarm visual affects in an area
*
* Updates the fire light on fire alarms in the area and sets all lights to emergency mode
*/
/area/proc/set_fire_alarm_effect()
fire = TRUE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
for(var/alarm in firealarms)
var/obj/machinery/firealarm/F = alarm
F.update_fire_light(fire)
for(var/obj/machinery/light/L in src)
L.update()
/**
* unset the fire alarm visual affects in an area
*
* Updates the fire light on fire alarms in the area and sets all lights to emergency mode
*/
/area/proc/unset_fire_alarm_effects()
fire = FALSE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
for(var/alarm in firealarms)
var/obj/machinery/firealarm/F = alarm
F.update_fire_light(fire)
for(var/obj/machinery/light/L in src)
L.update()
/area/proc/updateicon()
if((fire || eject || party) && (!requires_power||power_environ))//If it doesn't require power, can still activate this proc.
if(fire && !eject && !party)
if((eject || party) && (!requires_power||power_environ))//If it doesn't require power, can still activate this proc.
if(!eject && !party)
icon_state = "red"
else if(!fire && eject && !party)
else if(eject && !party)
icon_state = "red"
else if(party && !fire && !eject)
else if(party && !eject)
icon_state = "party"
else
icon_state = "blue-red"

View File

@@ -22,12 +22,14 @@
var/invuln = null
var/obj/item/camera_bug/bug = null
var/obj/item/camera_assembly/assembly = null
var/area/myarea = null
//OTHER
var/view_range = 7
var/short_range = 2
var/alarm_on = FALSE
var/busy = FALSE
var/emped = FALSE //Number of consecutive EMP's on this camera
@@ -44,6 +46,9 @@
GLOB.cameranet.cameras += src
GLOB.cameranet.addCamera(src)
if(isturf(loc))
myarea = get_area(src)
LAZYADD(myarea.cameras, src)
if(is_station_level(z) && prob(3) && !start_active)
toggle_cam(null, FALSE)
wires.CutAll()
@@ -59,10 +64,14 @@
QDEL_NULL(wires)
GLOB.cameranet.removeCamera(src) //Will handle removal from the camera network and the chunks, so we don't need to worry about that
GLOB.cameranet.cameras -= src
if(isarea(myarea))
LAZYREMOVE(myarea.cameras, src)
var/area/ai_monitored/A = get_area(src)
if(istype(A))
A.motioncamera = null
area_motion = null
cancelCameraAlarm()
cancelAlarm()
return ..()
/obj/machinery/camera/emp_act(severity)
@@ -282,9 +291,16 @@
status = !status
if(can_use())
GLOB.cameranet.addCamera(src)
if(isturf(loc))
myarea = get_area(src)
LAZYADD(myarea.cameras, src)
else
myarea = null
else
set_light(0)
GLOB.cameranet.removeCamera(src)
if(isarea(myarea))
LAZYREMOVE(myarea.cameras, src)
GLOB.cameranet.updateChunk(x, y, z)
var/change_msg = "deactivates"
if(status)
@@ -313,12 +329,14 @@
to_chat(O, "The screen bursts into static.")
/obj/machinery/camera/proc/triggerCameraAlarm()
if(is_station_contact(z))
SSalarms.camera_alarm.triggerAlarm(loc, src)
alarm_on = TRUE
for(var/mob/living/silicon/S in GLOB.silicon_mob_list)
S.triggerAlarm("Camera", get_area(src), list(src), src)
/obj/machinery/camera/proc/cancelCameraAlarm()
if(is_station_contact(z))
SSalarms.camera_alarm.clearAlarm(loc, src)
alarm_on = FALSE
for(var/mob/living/silicon/S in GLOB.silicon_mob_list)
S.cancelAlarm("Camera", get_area(src), src)
/obj/machinery/camera/proc/can_use()
if(!status)

View File

@@ -19,7 +19,8 @@
triggerAlarm()
else if(detectTime == -1)
for(var/mob/target in motionTargets)
if(target.stat == 2) lostTarget(target)
if(target.stat == 2)
lostTarget(target)
// If not detecting with motion camera...
if(!area_motion)
// See if the camera is still in range
@@ -42,19 +43,21 @@
cancelAlarm()
/obj/machinery/camera/proc/cancelAlarm()
if(!status || (stat & NOPOWER))
return FALSE
if(detectTime == -1 && is_station_contact(z))
SSalarms.motion_alarm.clearAlarm(loc, src)
if(detectTime == -1)
for(var/i in GLOB.silicon_mob_list)
var/mob/living/silicon/aiPlayer = i
if(status)
aiPlayer.cancelAlarm("Motion", get_area(src), src)
detectTime = 0
return TRUE
/obj/machinery/camera/proc/triggerAlarm()
if(!status || (stat & NOPOWER))
if(!detectTime)
return FALSE
if(!detectTime || !is_station_contact(z))
return FALSE
SSalarms.motion_alarm.triggerAlarm(loc, src)
for(var/mob/living/silicon/aiPlayer in GLOB.player_list)
if(status)
aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src)
visible_message("<span class='warning'>A red light flashes on the [src]!</span>")
detectTime = -1
return TRUE

View File

@@ -1,84 +1,88 @@
GLOBAL_LIST_EMPTY(priority_air_alarms)
GLOBAL_LIST_EMPTY(minor_air_alarms)
/obj/machinery/computer/atmos_alert
name = "atmospheric alert computer"
desc = "Used to access the station's atmospheric sensors."
circuit = /obj/item/circuitboard/atmos_alert
var/ui_x = 350
var/ui_y = 300
icon_keyboard = "atmos_key"
icon_screen = "alert:0"
light_color = LIGHT_COLOR_CYAN
var/list/priority_alarms = list()
var/list/minor_alarms = list()
var/receive_frequency = ATMOS_FIRE_FREQ
var/datum/radio_frequency/radio_connection
/obj/machinery/computer/atmos_alert/New()
..()
SSalarms.atmosphere_alarm.register(src, /obj/machinery/computer/station_alert/.proc/update_icon)
/obj/machinery/computer/atmos_alert/Initialize(mapload)
. = ..()
set_frequency(receive_frequency)
/obj/machinery/computer/atmos_alert/Destroy()
SSalarms.atmosphere_alarm.unregister(src)
return ..()
SSradio.remove_object(src, receive_frequency)
return ..()
/obj/machinery/computer/atmos_alert/attack_hand(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/atmos_alert/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/atmos_alert/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_alert.tmpl", src.name, 500, 500)
ui = new(user, src, ui_key, "AtmosAlertConsole", name, ui_x, ui_y, master_ui, state)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/atmos_alert/ui_data(mob/user, datum/topic_state/state)
var/data[0]
var/major_alarms[0]
var/minor_alarms[0]
/obj/machinery/computer/atmos_alert/tgui_data(mob/user)
var/list/data = list()
for(var/datum/alarm/alarm in SSalarms.atmosphere_alarm.major_alarms())
major_alarms[++major_alarms.len] = list("name" = sanitize(alarm.alarm_name()), "ref" = "\ref[alarm]")
for(var/datum/alarm/alarm in SSalarms.atmosphere_alarm.minor_alarms())
minor_alarms[++minor_alarms.len] = list("name" = sanitize(alarm.alarm_name()), "ref" = "\ref[alarm]")
data["priority_alarms"] = major_alarms
data["minor_alarms"] = minor_alarms
data["priority"] = list()
for(var/zone in priority_alarms)
data["priority"] += zone
data["minor"] = list()
for(var/zone in minor_alarms)
data["minor"] += zone
return data
/obj/machinery/computer/atmos_alert/update_icon()
var/list/alarms = SSalarms.atmosphere_alarm.major_alarms()
if(alarms.len)
icon_screen = "alert:2"
else
alarms = SSalarms.atmosphere_alarm.minor_alarms()
if(alarms.len)
icon_screen = "alert:1"
else
icon_screen = "alert:0"
..()
/obj/machinery/computer/atmos_alert/Topic(href, href_list)
/obj/machinery/computer/atmos_alert/tgui_act(action, params)
if(..())
return 1
return
switch(action)
if("clear")
var/zone = params["zone"]
if(zone in priority_alarms)
to_chat(usr, "<span class='notice'>Priority alarm for [zone] cleared.</span>")
priority_alarms -= zone
. = TRUE
if(zone in minor_alarms)
to_chat(usr, "<span class='notice'>Minor alarm for [zone] cleared.</span>")
minor_alarms -= zone
. = TRUE
update_icon()
if(href_list["clear_alarm"])
var/datum/alarm/alarm = locate(href_list["clear_alarm"]) in SSalarms.atmosphere_alarm.alarms
if(alarm)
for(var/datum/alarm_source/alarm_source in alarm.sources)
var/obj/machinery/alarm/air_alarm = alarm_source.source
if(istype(air_alarm))
var/list/new_ref = list("atmos_reset" = 1)
air_alarm.Topic(href, new_ref, state = GLOB.air_alarm_topic)
update_icon()
return 1
/obj/machinery/computer/atmos_alert/proc/set_frequency(new_frequency)
SSradio.remove_object(src, receive_frequency)
receive_frequency = new_frequency
radio_connection = SSradio.add_object(src, receive_frequency, filter = RADIO_ATMOSIA)
GLOBAL_DATUM_INIT(air_alarm_topic, /datum/topic_state/air_alarm_topic, new)
/obj/machinery/computer/atmos_alert/receive_signal(datum/signal/signal)
if(!signal)
return
/datum/topic_state/air_alarm_topic/href_list(var/mob/user)
var/list/extra_href = list()
extra_href["remote_connection"] = 1
extra_href["remote_access"] = 1
var/zone = signal.data["zone"]
var/severity = signal.data["alert"]
return extra_href
if(!zone || !severity)
return
/datum/topic_state/air_alarm_topic/can_use_topic(var/src_object, var/mob/user)
return STATUS_INTERACTIVE
minor_alarms -= zone
priority_alarms -= zone
if(severity == "severe")
priority_alarms += zone
else if (severity == "minor")
minor_alarms += zone
update_icon()
/obj/machinery/computer/atmos_alert/update_icon()
if(priority_alarms.len)
icon_screen = "alert:1"
else
icon_screen = "alert:0"
..()

View File

@@ -165,12 +165,9 @@
/obj/item/circuitboard/stationalert_engineering
name = "Circuit Board (Station Alert Console (Engineering))"
build_path = /obj/machinery/computer/station_alert
/obj/item/circuitboard/stationalert_security
name = "Circuit Board (Station Alert Console (Security))"
/obj/item/circuitboard/stationalert
name = "Circuit Board (Station Alert Console)"
build_path = /obj/machinery/computer/station_alert
/obj/item/circuitboard/stationalert_all
name = "Circuit Board (Station Alert Console (All))"
build_path = /obj/machinery/computer/station_alert/all
/obj/item/circuitboard/atmos_alert
name = "Circuit Board (Atmospheric Alert Computer)"
build_path = /obj/machinery/computer/atmos_alert

View File

@@ -6,48 +6,98 @@
icon_screen = "alert:0"
light_color = LIGHT_COLOR_CYAN
circuit = /obj/item/circuitboard/stationalert_engineering
var/datum/nano_module/alarm_monitor/alarm_monitor
var/monitor_type = /datum/nano_module/alarm_monitor/engineering
var/ui_x = 325
var/ui_y = 500
var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
/obj/machinery/computer/station_alert/security
monitor_type = /datum/nano_module/alarm_monitor/security
circuit = /obj/item/circuitboard/stationalert_security
/obj/machinery/computer/station_alert/all
monitor_type = /datum/nano_module/alarm_monitor/all
circuit = /obj/item/circuitboard/stationalert_all
/obj/machinery/computer/station_alert/New()
..()
alarm_monitor = new monitor_type(src)
alarm_monitor.register(src, /obj/machinery/computer/station_alert/.proc/update_icon)
/obj/machinery/computer/station_alert/Initialize(mapload)
. = ..()
GLOB.alert_consoles += src
/obj/machinery/computer/station_alert/Destroy()
alarm_monitor.unregister(src)
QDEL_NULL(alarm_monitor)
GLOB.alert_consoles -= src
return ..()
/obj/machinery/computer/station_alert/attack_ai(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
interact(user)
tgui_interact(user)
/obj/machinery/computer/station_alert/attack_hand(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
interact(user)
tgui_interact(user)
/obj/machinery/computer/station_alert/interact(mob/user)
alarm_monitor.ui_interact(user)
/obj/machinery/computer/station_alert/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "StationAlertConsole", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/computer/station_alert/tgui_data(mob/user)
var/list/data = list()
data["alarms"] = list()
for(var/class in alarms)
data["alarms"][class] = list()
for(var/area in alarms[class])
data["alarms"][class] += area
return data
/obj/machinery/computer/station_alert/proc/triggerAlarm(class, area/A, O, obj/source)
if(source.z != z)
return
if(stat & (BROKEN))
return
var/list/L = alarms[class]
for(var/I in L)
if(I == A.name)
var/list/alarm = L[I]
var/list/sources = alarm[3]
if(!(source in sources))
sources += source
return TRUE
var/obj/machinery/camera/C = null
var/list/CL = null
if(O && islist(O))
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(source))
return TRUE
/obj/machinery/computer/station_alert/proc/cancelAlarm(class, area/A, obj/origin)
if(stat & (BROKEN))
return
var/list/L = alarms[class]
var/cleared = FALSE
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 = TRUE
L -= I
return !cleared
/obj/machinery/computer/station_alert/update_icon()
if(alarm_monitor)
var/list/alarms = alarm_monitor.major_alarms()
if(alarms.len)
icon_screen = "alert:2"
else
icon_screen = "alert:0"
var/active_alarms = FALSE
for(var/cat in alarms)
var/list/L = alarms[cat]
if(L.len)
active_alarms = TRUE
if(active_alarms)
icon_screen = "alert:2"
else
icon_screen = "alert:0"
..()

View File

@@ -28,6 +28,11 @@
var/nextstate = null
var/boltslocked = TRUE
var/active_alarm = FALSE
var/list/affecting_areas
/obj/machinery/door/firedoor/Initialize(mapload)
. = ..()
CalculateAffectingAreas()
/obj/machinery/door/firedoor/examine(mob/user)
. = ..()
@@ -40,11 +45,31 @@
else
. += "<span class='notice'>The bolt locks have been <i>unscrewed</i>, but the bolts themselves are still <b>wrenched</b> to the floor.</span>"
/obj/machinery/door/firedoor/proc/CalculateAffectingAreas()
remove_from_areas()
affecting_areas = get_adjacent_open_areas(src) | get_area(src)
for(var/I in affecting_areas)
var/area/A = I
LAZYADD(A.firedoors, src)
/obj/machinery/door/firedoor/closed
icon_state = "door_closed"
opacity = TRUE
density = TRUE
//see also turf/AfterChange for adjacency shennanigans
/obj/machinery/door/firedoor/proc/remove_from_areas()
if(affecting_areas)
for(var/I in affecting_areas)
var/area/A = I
LAZYREMOVE(A.firedoors, src)
/obj/machinery/door/firedoor/Destroy()
remove_from_areas()
affecting_areas.Cut()
return ..()
/obj/machinery/door/firedoor/Bumped(atom/AM)
if(panel_open || operating)
return

View File

@@ -25,12 +25,18 @@ FIRE ALARM
active_power_usage = 6
power_channel = ENVIRON
resistance_flags = FIRE_PROOF
light_power = 0
light_range = 7
light_color = "#ff3232"
var/last_process = 0
var/wiresexposed = 0
var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
var/report_fire_alarms = TRUE // Should triggered fire alarms also trigger an actual alarm?
var/show_alert_level = TRUE // Should fire alarms display the current alert level?
var/area/myarea = null
/obj/machinery/firealarm/no_alarm
report_fire_alarms = FALSE
@@ -191,6 +197,7 @@ FIRE ALARM
/obj/machinery/firealarm/obj_break(damage_flag)
if(!(stat & BROKEN) && !(flags & NODECONSTRUCT) && buildstage != 0) //can't break the electronics if there isn't any inside.
stat |= BROKEN
LAZYREMOVE(myarea.firealarms, src)
update_icon()
/obj/machinery/firealarm/deconstruct(disassembled = TRUE)
@@ -203,6 +210,14 @@ FIRE ALARM
new /obj/item/stack/cable_coil(loc, 3)
qdel(src)
/obj/machinery/firealarm/proc/update_fire_light(fire)
if(fire == !!light_power)
return // do nothing if we're already active
if(fire)
set_light(l_power = 0.8)
else
set_light(l_power = 0)
/obj/machinery/firealarm/process()//Note: this processing was mostly phased out due to other code, and only runs when needed
if(stat & (NOPOWER|BROKEN))
return
@@ -289,23 +304,13 @@ FIRE ALARM
if(!working)
return
var/area/A = get_area(src)
A.fire_reset()
A.firereset(src)
for(var/obj/machinery/firealarm/FA in A)
if(is_station_contact(z) && FA.report_fire_alarms)
SSalarms.fire_alarm.clearAlarm(loc, FA)
/obj/machinery/firealarm/proc/alarm(var/duration = 0)
/obj/machinery/firealarm/proc/alarm()
if(!working)
return
var/area/A = get_area(src)
for(var/obj/machinery/firealarm/FA in A)
if(is_station_contact(z) && FA.report_fire_alarms)
SSalarms.fire_alarm.triggerAlarm(loc, FA, duration)
else
A.fire_alert() // Manually trigger alarms if the alarm isn't reported
A.firealert(src) // Manually trigger alarms if the alarm isn't reported
update_icon()
/obj/machinery/firealarm/New(location, direction, building)
@@ -323,8 +328,14 @@ FIRE ALARM
else
overlays += image('icons/obj/monitors.dmi', "overlay_green")
myarea = get_area(src)
LAZYADD(myarea.firealarms, src)
update_icon()
/obj/machinery/firealarm/Destroy()
LAZYREMOVE(myarea.firealarms, src)
return ..()
/*
FIRE ALARM CIRCUIT
Just a object used in constructing fire alarms

View File

@@ -221,6 +221,12 @@
A.contents += thing
thing.change_area(old_area, A)
var/area/oldA = get_area(get_turf(usr))
var/list/firedoors = oldA.firedoors
for(var/door in firedoors)
var/obj/machinery/door/firedoor/FD = door
FD.CalculateAffectingAreas()
interact()
area_created = TRUE
return area_created
@@ -236,6 +242,10 @@
return
set_area_machinery_title(A,str,prevname)
A.name = str
if(A.firedoors)
for(var/D in A.firedoors)
var/obj/machinery/door/firedoor/FD = D
FD.CalculateAffectingAreas()
to_chat(usr, "<span class='notice'>You rename the '[prevname]' to '[str]'.</span>")
interact()
return 1

View File

@@ -277,6 +277,13 @@
if(SSair && !ignore_air)
SSair.add_to_active(src)
//update firedoor adjacency
var/list/turfs_to_check = get_adjacent_open_turfs(src) | src
for(var/I in turfs_to_check)
var/turf/T = I
for(var/obj/machinery/door/firedoor/FD in T)
FD.CalculateAffectingAreas()
if(!keep_cabling && !can_have_cabling())
for(var/obj/structure/cable/C in contents)
qdel(C)

View File

@@ -1,136 +0,0 @@
#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)
var/duration = 0 // How long this source will be alarming, 0 for indefinetely.
var/severity = 1 // How severe the alarm from this source is.
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
start_time = world.time
source_name = source.get_source_name()
/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).
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, var/severity)
src.origin = origin
cameras() // Sets up both cameras and last alarm area.
set_source_data(source, duration, severity)
/datum/alarm/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_source_data(var/atom/source, var/duration, var/severity)
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 = duration SECONDS
AS.duration = duration
AS.severity = severity
/datum/alarm/proc/clear(var/source)
var/datum/alarm_source/AS = sources_assoc[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/alarm_name()
if(!origin)
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 ? origin.get_alarm_cameras() : last_area.get_alarm_cameras()
last_camera_area = last_area
return cameras
/datum/alarm/proc/max_severity()
var/max_severity = 0
for(var/datum/alarm_source/AS in sources)
max_severity = max(AS.severity, max_severity)
return max_severity
/******************
* Assisting procs *
******************/
/atom/proc/get_alarm_area()
var/area/A = get_area(src)
return A
/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()
/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()

View File

@@ -1,103 +0,0 @@
#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 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/process()
for(var/datum/alarm/A in alarms)
A.process()
check_alarm_cleared(A)
/datum/alarm_handler/proc/triggerAlarm(var/atom/origin, var/atom/source, var/duration = 0, var/severity = 1)
var/new_alarm
//Proper origin and source mandatory
if(!(origin && source))
return
origin = origin.get_alarm_origin()
new_alarm = 0
//see if there is already an alarm of this origin
var/datum/alarm/existing = alarms_assoc[origin]
if(existing)
existing.set_source_data(source, duration, severity)
else
existing = new/datum/alarm(origin, source, duration, severity)
new_alarm = 1
alarms |= existing
alarms_assoc[origin] = existing
if(new_alarm)
alarms = dd_sortedObjectList(alarms)
on_alarm_change(existing, ALARM_RAISED)
return new_alarm
/datum/alarm_handler/proc/clearAlarm(var/atom/origin, var/source)
//Proper origin and source mandatory
if(!(origin && source))
return
origin = origin.get_alarm_origin()
var/datum/alarm/existing = alarms_assoc[origin]
if(existing)
existing.clear(source)
return check_alarm_cleared(existing)
/datum/alarm_handler/proc/has_major_alarms()
if(alarms && alarms.len)
return 1
return 0
/datum/alarm_handler/proc/major_alarms()
return alarms
/datum/alarm_handler/proc/minor_alarms()
return alarms
/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
on_alarm_change(alarm, ALARM_CLEARED)
return 1
return 0
/datum/alarm_handler/proc/on_alarm_change(var/datum/alarm/alarm, var/was_raised)
for(var/obj/machinery/camera/C in alarm.cameras())
if(was_raised)
C.network.Add(category)
else
C.network.Remove(category)
notify_listeners(alarm, was_raised)
/datum/alarm_handler/proc/get_alarm_severity_for_origin(var/atom/origin)
if(!origin)
return
origin = origin.get_alarm_origin()
var/datum/alarm/existing = alarms_assoc[origin]
if(!existing)
return
return existing.max_severity()
/atom/proc/get_alarm_origin()
return src
/turf/get_alarm_origin()
var/area/area = get_area(src)
return area // Very important to get area.master, as dynamic lightning can and will split areas.
/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)

View File

@@ -1,19 +0,0 @@
/datum/alarm_handler/atmosphere
category = "Atmosphere Alarms"
/datum/alarm_handler/atmosphere/triggerAlarm(var/atom/origin, var/atom/source, var/duration = 0, var/severity = 1)
..()
/datum/alarm_handler/atmosphere/major_alarms()
var/list/major_alarms = new()
for(var/datum/alarm/A in alarms)
if(A.max_severity() > 1)
major_alarms.Add(A)
return major_alarms
/datum/alarm_handler/atmosphere/minor_alarms()
var/list/minor_alarms = new()
for(var/datum/alarm/A in alarms)
if(A.max_severity() == 1)
minor_alarms.Add(A)
return minor_alarms

View File

@@ -1,2 +0,0 @@
/datum/alarm_handler/burglar
category = "Burglar Alarms"

View File

@@ -1,2 +0,0 @@
/datum/alarm_handler/camera
category = "Camera Alarms"

View File

@@ -1,11 +0,0 @@
/datum/alarm_handler/fire
category = "Fire Alarms"
/datum/alarm_handler/fire/on_alarm_change(var/datum/alarm/alarm, var/was_raised)
var/area/A = alarm.origin
if(istype(A))
if(was_raised)
A.fire_alert()
else
A.fire_reset()
..()

View File

@@ -1,2 +0,0 @@
/datum/alarm_handler/motion
category = "Motion Alarms"

View File

@@ -1,10 +0,0 @@
/datum/alarm_handler/power
category = "Power Alarms"
/datum/alarm_handler/power/on_alarm_change(var/datum/alarm/alarm, var/was_raised)
var/area/A = alarm.origin
if(istype(A))
A.power_alert(was_raised)
..()
/area/proc/power_alert(var/alarming)

View File

@@ -241,6 +241,39 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
return
show_borg_info()
/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=[UID()];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/area/A = alm[1]
var/C = alm[2]
var/list/sources = alm[3]
dat += "<NOBR>"
if(C && istype(C, /list))
var/dat2 = ""
for (var/obj/machinery/camera/I in C)
dat2 += text("[]<A HREF=?src=[UID()];switchcamera=[I.UID()]>[]</A>", (dat2=="") ? "" : " | ", I.c_tag)
dat += text("-- [] ([])", 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=[UID()];switchcamera=[Ctmp.UID()]>[]</A>)", A.name, Ctmp.c_tag)
else
dat += text("-- [] (No Camera)", A.name)
if(sources.len > 1)
dat += text("- [] sources", sources.len)
dat += "</NOBR><BR>\n"
else
dat += "-- All Systems Nominal<BR>\n"
dat += "<BR>\n"
viewalerts = TRUE
src << browse(dat, "window=aialerts&can_close=0")
/mob/living/silicon/ai/proc/show_borg_info()
stat(null, text("Connected cyborgs: [connected_robots.len]"))
for(var/mob/living/silicon/robot/R in connected_robots)
@@ -608,8 +641,8 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
src << browse(null, t1)
if(href_list["switchcamera"])
switchCamera(locate(href_list["switchcamera"])) in GLOB.cameranet.cameras
if(href_list["showalerts"])
subsystem_alarm_monitor()
if (href_list["showalerts"])
ai_alerts()
if(href_list["show_paper"])
if(last_paper_seen)
src << browse(last_paper_seen, "window=show_paper")
@@ -784,6 +817,62 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
Bot.call_bot(src, waypoint)
/mob/living/silicon/ai/triggerAlarm(class, area/A, O, obj/alarmsource)
if(alarmsource.z != z)
return
var/list/L = 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))
if (O)
if (C && C.can_use())
queueAlarm("--- [class] alarm detected in [A.name]! (<A HREF=?src=[UID()];switchcamera=[C.UID()]>[C.c_tag]</A>)", class)
else if (CL && CL.len)
var/foo = 0
var/dat2 = ""
for (var/obj/machinery/camera/I in CL)
dat2 += text("[]<A HREF=?src=[UID()];switchcamera=[I.UID()]>[]</A>", (!foo) ? "" : " | ", I.c_tag) //I'm not fixing this shit...
foo = 1
queueAlarm(text ("--- [] alarm detected in []! ([])", class, A.name, dat2), class)
else
queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class)
else
queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class)
if(viewalerts)
ai_alerts()
return 1
/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/switchCamera(obj/machinery/camera/C)
if(!tracking)

View File

@@ -132,8 +132,6 @@
sleep(50)
theAPC = null
process_queued_alarms()
/mob/living/silicon/ai/updatehealth(reason = "none given")
if(status_flags & GODMODE)
health = 100

View File

@@ -13,7 +13,6 @@
handle_robot_cell()
process_locks()
update_items()
process_queued_alarms()
/mob/living/silicon/robot/proc/handle_robot_cell()

View File

@@ -540,6 +540,34 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
src.verbs -= GLOB.robot_verbs_default
src.verbs -= silicon_subsystems
/mob/living/silicon/robot/verb/cmd_robot_alerts()
set category = "Robot Commands"
set name = "Show Alerts"
if(usr.stat == DEAD)
to_chat(src, "<span class='userdanger'>Alert: You are dead.</span>")
return //won't work if dead
robot_alerts()
/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/area/A = alm[1]
dat += "<NOBR>"
dat += text("-- [A.name]")
dat += "</NOBR><BR>\n"
else
dat += "-- All Systems Nominal<BR>\n"
dat += "<BR>\n"
var/datum/browser/alerts = new(usr, "robotalerts", "Current Station Alerts", 400, 410)
alerts.set_content(dat)
alerts.open()
/mob/living/silicon/robot/proc/ionpulse()
if(!ionpulse_on)
return
@@ -601,6 +629,47 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
/mob/living/silicon/robot/InCritical()
return low_power_mode
/mob/living/silicon/robot/triggerAlarm(class, area/A, O, obj/alarmsource)
if(alarmsource.z != z)
return
if(stat == DEAD)
return 1
var/list/L = 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))
queueAlarm(text("--- [class] alarm detected in [A.name]!"), class)
return 1
/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/ex_act(severity)
switch(severity)
if(1.0)
@@ -1020,10 +1089,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
src << browse(null, t1)
return 1
if(href_list["showalerts"])
subsystem_alarm_monitor()
return 1
if(href_list["mod"])
var/obj/item/O = locate(href_list["mod"])
if(istype(O) && (O.loc == src))
@@ -1038,6 +1103,10 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
activate_module(O)
installed_modules()
//Show alerts window if user clicked on "Show alerts" in chat
if(href_list["showalerts"])
robot_alerts()
if(href_list["deact"])
var/obj/item/O = locate(href_list["deact"])
if(activated(O))

View File

@@ -11,9 +11,10 @@
var/list/stating_laws = list()// Channels laws are currently being stated on
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)
//var/list/hud_list[10]
var/list/speech_synthesizer_langs = list() //which languages can be vocalized by the speech synthesizer
var/list/alarm_handlers = list() // List of alarm handlers this silicon is registered to
var/designation = ""
var/obj/item/camera/siliconcam/aiCamera = null //photography
//Used in say.dm, allows for pAIs to have different say flavor text, as well as silicons, although the latter is not implemented.
@@ -25,9 +26,6 @@
//var/sensor_mode = 0 //Determines the current HUD.
var/next_alarm_notice
var/list/datum/alarm/queued_alarms = new()
hud_possible = list(SPECIALROLE_HUD, DIAG_STAT_HUD, DIAG_HUD)
@@ -55,10 +53,90 @@
/mob/living/silicon/Destroy()
GLOB.silicon_mob_list -= src
for(var/datum/alarm_handler/AH in alarm_handlers)
AH.unregister(src)
return ..()
/mob/living/silicon/proc/cancelAlarm()
return
/mob/living/silicon/proc/triggerAlarm()
return
/mob/living/silicon/proc/queueAlarm(message, type, 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)
return
addtimer(CALLBACK(src, .proc/show_alarms), 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)
var/msg = "--- "
if(alarm_types_show["Burglar"])
msg += "BURGLAR: [alarm_types_show["Burglar"]] alarms detected. - "
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=[UID()];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=[UID()];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/rename_character(oldname, newname)
// we actually don't want it changing minds and stuff
if(!newname)
@@ -283,63 +361,6 @@
if("Disable")
to_chat(src, "Sensor augmentations disabled.")
/mob/living/silicon/proc/receive_alarm(var/datum/alarm_handler/alarm_handler, var/datum/alarm/alarm, was_raised)
if(!next_alarm_notice)
next_alarm_notice = world.time + 10 SECONDS
var/list/alarms = queued_alarms[alarm_handler]
if(was_raised)
// Raised alarms are always set
alarms[alarm] = 1
else
// Alarms that were raised but then cleared before the next notice are instead removed
if(alarm in alarms)
alarms -= alarm
// And alarms that have only been cleared thus far are set as such
else
alarms[alarm] = -1
/mob/living/silicon/proc/process_queued_alarms()
if(next_alarm_notice && (world.time > next_alarm_notice))
next_alarm_notice = 0
var/alarm_raised = 0
for(var/datum/alarm_handler/AH in queued_alarms)
var/list/alarms = queued_alarms[AH]
var/reported = 0
for(var/datum/alarm/A in alarms)
if(alarms[A] == 1)
if(!reported)
reported = 1
to_chat(src, "<span class='warning'>--- [AH.category] Detected ---</span>")
raised_alarm(A)
for(var/datum/alarm_handler/AH in queued_alarms)
var/list/alarms = queued_alarms[AH]
var/reported = 0
for(var/datum/alarm/A in alarms)
if(alarms[A] == -1)
if(!reported)
reported = 1
to_chat(src, "<span class='notice'>--- [AH.category] Cleared ---</span>")
to_chat(src, "\The [A.alarm_name()].")
if(alarm_raised)
to_chat(src, "<A HREF=?src=[UID()];showalerts=1>\[Show Alerts\]</A>")
for(var/datum/alarm_handler/AH in queued_alarms)
var/list/alarms = queued_alarms[AH]
alarms.Cut()
/mob/living/silicon/proc/raised_alarm(var/datum/alarm/A)
to_chat(src, "[A.alarm_name()]!")
/mob/living/silicon/ai/raised_alarm(var/datum/alarm/A)
var/cameratext = ""
for(var/obj/machinery/camera/C in A.cameras())
cameratext += "[(cameratext == "")? "" : "|"]<A HREF=?src=[UID()];switchcamera=\ref[C]>[C.c_tag]</A>"
to_chat(src, "[A.alarm_name()]! ([(cameratext)? cameratext : "No Camera"])")
/mob/living/silicon/adjustToxLoss(var/amount)
return STATUS_UPDATE_NONE

View File

@@ -8,13 +8,11 @@
/mob/living/silicon
var/list/silicon_subsystems = list(
/mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_law_manager
)
/mob/living/silicon/ai
silicon_subsystems = list(
/mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_atmos_control,
/mob/living/silicon/proc/subsystem_crew_monitor,
/mob/living/silicon/proc/subsystem_law_manager,
@@ -23,7 +21,6 @@
/mob/living/silicon/robot/drone
silicon_subsystems = list(
/mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_law_manager,
/mob/living/silicon/proc/subsystem_power_monitor
)
@@ -32,30 +29,11 @@
register_alarms = 0
/mob/living/silicon/proc/init_subsystems()
alarm_monitor = new(src)
atmos_control = new(src)
crew_monitor = new(src)
law_manager = new(src)
power_monitor = new(src)
if(!register_alarms)
return
var/list/register_to = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
for(var/datum/alarm_handler/AH in register_to)
AH.register(src, /mob/living/silicon/proc/receive_alarm)
queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order
alarm_handlers |= AH
/********************
* Alarm Monitor *
********************/
/mob/living/silicon/proc/subsystem_alarm_monitor()
set name = "Alarm Monitor"
set category = "Subsystems"
alarm_monitor.ui_interact(usr, state = GLOB.self_state)
/********************
* Atmos Control *
********************/

View File

@@ -35,7 +35,7 @@
/obj/machinery/modular_computer/console/preset/engineering/install_programs()
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/power_monitor())
hard_drive.store_file(new/datum/computer_file/program/alarm_monitor())
// hard_drive.store_file(new/datum/computer_file/program/alarm_monitor()) //TO-DO:TGUI--Uncomment Modular computers
hard_drive.store_file(new/datum/computer_file/program/supermatter_monitor())
// ===== RESEARCH CONSOLE =====

View File

@@ -7,65 +7,103 @@
requires_ntnet = 1
network_destination = "alarm monitoring network"
size = 5
var/list/datum/alarm_handler/alarm_handlers
var/tgui_id = "NtosStationAlertConsole"
var/ui_x = 315
var/ui_y = 500
/datum/computer_file/program/alarm_monitor/New()
var/has_alert = 0
var/alarms = list("Fire" = list(), "Atmosphere" = list(), "Power" = list())
/datum/computer_file/program/alarm_monitor/process_tick()
..()
alarm_handlers = list(SSalarms.atmosphere_alarm, SSalarms.fire_alarm, SSalarms.power_alarm)
for(var/datum/alarm_handler/AH in alarm_handlers)
AH.register(src, /datum/computer_file/program/alarm_monitor/proc/update_icon)
/datum/computer_file/program/alarm_monitor/Destroy()
for(var/datum/alarm_handler/AH in alarm_handlers)
AH.unregister(src)
QDEL_NULL(alarm_handlers)
return ..()
/datum/computer_file/program/alarm_monitor/proc/update_icon()
for(var/datum/alarm_handler/AH in alarm_handlers)
if(AH.has_major_alarms())
program_icon_state = "alert-red"
ui_header = "alarm_red.gif"
if(has_alert)
program_icon_state = "alert-red"
ui_header = "alarm_red.gif"
update_computer_icon()
else
if(!has_alert)
program_icon_state = "alert-green"
ui_header = "alarm_green.gif"
update_computer_icon()
return 1
program_icon_state = "alert-green"
ui_header = "alarm_green.gif"
update_computer_icon()
return 0
return 1
/datum/computer_file/program/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring", 575, 700)
ui.set_auto_update(1)
ui.set_layout_key("program")
ui.open()
/datum/computer_file/program/alarm_monitor/ui_data(mob/user)
/datum/computer_file/program/alarm_monitor/tgui_data(mob/user)
var/list/data = get_header_data()
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.major_alarms())
var/cameras[0]
var/lost_sources[0]
if(isAI(user))
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" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : ""))
data["categories"] = categories
data["alarms"] = list()
for(var/class in alarms)
data["alarms"][class] = list()
for(var/area in alarms[class])
data["alarms"][class] += area
return data
/datum/computer_file/program/alarm_monitor/proc/triggerAlarm(class, area/A, O, obj/source)
if(is_station_level(source.z))
if(!(A.type in GLOB.the_station_areas))
return
else if(!is_mining_level(source.z) || istype(A, /area/ruin))
return
var/list/L = alarms[class]
for(var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/sources = alarm[3]
if (!(source in sources))
sources += source
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(source))
update_alarm_display()
return 1
/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()
has_alert = FALSE
for(var/cat in alarms)
var/list/L = alarms[cat]
if(L.len)
has_alert = TRUE
/datum/computer_file/program/alarm_monitor/run_program(mob/user)
. = ..(user)
GLOB.alarmdisplay += src
/datum/computer_file/program/alarm_monitor/kill_program(forced = FALSE)
GLOB.alarmdisplay -= src
..()

View File

@@ -1,90 +0,0 @@
/datum/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. Currently really only for AI-use.
var/list/datum/alarm_handler/alarm_handlers // The particular list of alarm handlers this alarm monitor should present to the user.
/datum/nano_module/alarm_monitor/all/New()
..()
alarm_handlers = list(SSalarms.atmosphere_alarm, SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.fire_alarm, SSalarms.motion_alarm, SSalarms.power_alarm)
/datum/nano_module/alarm_monitor/engineering/New()
..()
alarm_handlers = list(SSalarms.atmosphere_alarm, SSalarms.fire_alarm, SSalarms.power_alarm)
/datum/nano_module/alarm_monitor/security/New()
..()
alarm_handlers = list(SSalarms.burglar_alarm, SSalarms.camera_alarm, SSalarms.motion_alarm)
/datum/nano_module/alarm_monitor/proc/register(var/object, var/procName)
for(var/datum/alarm_handler/AH in alarm_handlers)
AH.register(object, procName)
/datum/nano_module/alarm_monitor/proc/unregister(var/object)
for(var/datum/alarm_handler/AH in alarm_handlers)
AH.unregister(object)
/datum/nano_module/alarm_monitor/proc/all_alarms()
var/list/all_alarms = new()
for(var/datum/alarm_handler/AH in alarm_handlers)
all_alarms += AH.alarms
return all_alarms
/datum/nano_module/alarm_monitor/proc/major_alarms()
var/list/all_alarms = new()
for(var/datum/alarm_handler/AH in alarm_handlers)
all_alarms += AH.major_alarms()
return all_alarms
/datum/nano_module/alarm_monitor/proc/minor_alarms()
var/list/all_alarms = new()
for(var/datum/alarm_handler/AH in alarm_handlers)
all_alarms += AH.minor_alarms()
return all_alarms
/datum/nano_module/alarm_monitor/Topic(ref, href_list)
if(..())
return 1
if(href_list["switchTo"])
var/obj/machinery/camera/C = locate(href_list["switchTo"]) in GLOB.cameranet.cameras
if(!C || !isAI(usr))
return
usr.switch_to_camera(C)
return 1
/datum/nano_module/alarm_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "alarm_monitor.tmpl", "Alarm Monitoring Console", 800, 800, state = state)
ui.open()
ui.set_auto_update(1)
/datum/nano_module/alarm_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
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.major_alarms())
var/cameras[0]
var/lost_sources[0]
if(isAI(user))
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" = lost_sources.len ? sanitize(english_list(lost_sources, nothing_text = "", and_text = ", ")) : ""))
data["categories"] = categories
return data

View File

@@ -1195,31 +1195,27 @@
lighting = autoset(lighting, 1)
environ = autoset(environ, 1)
autoflag = 3
if(report_power_alarm && is_station_contact(z))
SSalarms.power_alarm.clearAlarm(loc, src)
area.poweralert(1, src)
else if(cell.charge < 1250 && cell.charge > 750 && longtermpower < 0) // <30%, turn off equipment
if(autoflag != 2)
equipment = autoset(equipment, 2)
lighting = autoset(lighting, 1)
environ = autoset(environ, 1)
if(report_power_alarm && is_station_contact(z))
SSalarms.power_alarm.triggerAlarm(loc, src)
area.poweralert(0, src)
autoflag = 2
else if(cell.charge < 750 && cell.charge > 10) // <15%, turn off lighting & equipment
if((autoflag > 1 && longtermpower < 0) || (autoflag > 1 && longtermpower >= 0))
equipment = autoset(equipment, 2)
lighting = autoset(lighting, 2)
environ = autoset(environ, 1)
if(report_power_alarm && is_station_contact(z))
SSalarms.power_alarm.triggerAlarm(loc, src)
area.poweralert(0, src)
autoflag = 1
else if(cell.charge <= 0) // zero charge, turn all off
if(autoflag != 0)
equipment = autoset(equipment, 0)
lighting = autoset(lighting, 0)
environ = autoset(environ, 0)
if(report_power_alarm && is_station_contact(z))
SSalarms.power_alarm.triggerAlarm(loc, src)
area.poweralert(0, src)
autoflag = 0
// now trickle-charge the cell
@@ -1274,8 +1270,7 @@
equipment = autoset(equipment, 0)
lighting = autoset(lighting, 0)
environ = autoset(environ, 0)
if(report_power_alarm && is_station_contact(z))
SSalarms.power_alarm.triggerAlarm(loc, src)
area.poweralert(0, src)
autoflag = 0
// update icon & area power if anything changed

View File

@@ -177,6 +177,8 @@
var/nightshift_light_power = 0.45
var/nightshift_light_color = "#FFDDCC"
var/bulb_emergency_colour = "#FF3232" // determines the colour of the light while it's in emergency mode
// the smaller bulb light fixture
/obj/machinery/light/small
@@ -238,7 +240,11 @@
switch(status) // set icon_states
if(LIGHT_OK)
icon_state = "[base_state][on]"
var/area/A = get_area(src)
if(A && A.fire)
icon_state = "[base_state]_emergency"
else
icon_state = "[base_state][on]"
if(LIGHT_EMPTY)
icon_state = "[base_state]-empty"
on = FALSE
@@ -260,10 +266,20 @@
on = FALSE
update_icon()
if(on)
var/BR = nightshift_enabled ? nightshift_light_range : brightness_range
var/PO = nightshift_enabled ? nightshift_light_power : brightness_power
var/CO = nightshift_enabled ? nightshift_light_color : brightness_color
var/matching = light_range == BR && light_power == PO && light_color == CO
var/BR = brightness_range
var/PO = brightness_power
var/CO = brightness_color
if(color)
CO = color
var/area/A = get_area(src)
if(A && A.fire)
CO = bulb_emergency_colour
else if(nightshift_enabled)
BR = nightshift_light_range
PO = nightshift_light_power
if(!color)
CO = nightshift_light_color
var/matching = light && BR == light.light_range && PO == light.light_power && CO == light.light_color
if(!matching)
switchcount++
if(rigged)

View File

@@ -1,4 +0,0 @@
/area/engine/engineering/power_alert(var/alarming)
if(alarming)
investigate_log("has a power alarm!","singulo")
..()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

View File

@@ -215,7 +215,6 @@
#include "code\controllers\subsystem\acid.dm"
#include "code\controllers\subsystem\afk.dm"
#include "code\controllers\subsystem\air.dm"
#include "code\controllers\subsystem\alarm.dm"
#include "code\controllers\subsystem\assets.dm"
#include "code\controllers\subsystem\atoms.dm"
#include "code\controllers\subsystem\changelog.dm"
@@ -1247,14 +1246,6 @@
#include "code\modules\admin\verbs\SDQL2\SDQL_2.dm"
#include "code\modules\admin\verbs\SDQL2\SDQL_2_parser.dm"
#include "code\modules\admin\verbs\SDQL2\useful_procs.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\burglar_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\antagonists\_common\antag_datum.dm"
#include "code\modules\antagonists\_common\antag_helpers.dm"
#include "code\modules\antagonists\_common\antag_hud.dm"
@@ -2097,7 +2088,6 @@
#include "code\modules\modular_computers\file_system\programs\antagonist\revelation.dm"
#include "code\modules\modular_computers\file_system\programs\command\card.dm"
#include "code\modules\modular_computers\file_system\programs\command\comms.dm"
#include "code\modules\modular_computers\file_system\programs\engineering\alarm.dm"
#include "code\modules\modular_computers\file_system\programs\engineering\power_monitor.dm"
#include "code\modules\modular_computers\file_system\programs\engineering\sm_monitor.dm"
#include "code\modules\modular_computers\file_system\programs\generic\configurator.dm"
@@ -2136,7 +2126,6 @@
#include "code\modules\nano\interaction\physical.dm"
#include "code\modules\nano\interaction\self.dm"
#include "code\modules\nano\interaction\zlevel.dm"
#include "code\modules\nano\modules\alarm_monitor.dm"
#include "code\modules\nano\modules\atmos_control.dm"
#include "code\modules\nano\modules\ert_manager.dm"
#include "code\modules\nano\modules\human_appearance.dm"
@@ -2203,7 +2192,6 @@
#include "code\modules\power\singularity\emitter.dm"
#include "code\modules\power\singularity\field_generator.dm"
#include "code\modules\power\singularity\generator.dm"
#include "code\modules\power\singularity\investigate.dm"
#include "code\modules\power\singularity\narsie.dm"
#include "code\modules\power\singularity\singularity.dm"
#include "code\modules\power\singularity\particle_accelerator\particle.dm"

View File

@@ -0,0 +1,47 @@
import { useBackend } from '../backend';
import { Button, Section } from '../components';
import { Window } from '../layouts';
export const AtmosAlertConsole = (props, context) => {
const { act, data } = useBackend(context);
const priorityAlerts = data.priority || [];
const minorAlerts = data.minor || [];
return (
<Window resizable>
<Window.Content scrollable>
<Section title="Alarms">
<ul>
{priorityAlerts.length === 0 && (
<li className="color-good">
No Priority Alerts
</li>
)}
{priorityAlerts.map(alert => (
<li key={alert}>
<Button
icon="times"
content={alert}
color="bad"
onClick={() => act('clear', { zone: alert })} />
</li>
))}
{minorAlerts.length > 0 && (
<li className="color-good">
No Minor Alerts
</li>
)}
{minorAlerts.map(alert => (
<li key={alert}>
<Button
icon="times"
content={alert}
color="average"
onClick={() => act('clear', { zone: alert })} />
</li>
))}
</ul>
</Section>
</Window.Content>
</Window>
);
};

View File

@@ -0,0 +1,12 @@
import { NtosWindow } from '../layouts';
import { StationAlertConsoleContent } from './StationAlertConsole';
export const NtosStationAlertConsole = () => {
return (
<NtosWindow resizable>
<NtosWindow.Content scrollable>
<StationAlertConsoleContent />
</NtosWindow.Content>
</NtosWindow>
);
};

View File

@@ -0,0 +1,68 @@
import { Fragment } from 'inferno';
import { useBackend } from '../backend';
import { Section } from '../components';
import { Window } from '../layouts';
export const StationAlertConsole = () => {
return (
<Window resizable>
<Window.Content scrollable>
<StationAlertConsoleContent />
</Window.Content>
</Window>
);
};
export const StationAlertConsoleContent = (props, context) => {
const { data } = useBackend(context);
const categories = data.alarms || [];
const fire = categories['Fire'] || [];
const atmos = categories['Atmosphere'] || [];
const power = categories['Power'] || [];
return (
<Fragment>
<Section title="Fire Alarms">
<ul>
{fire.length === 0 && (
<li className="color-good">
Systems Nominal
</li>
)}
{fire.map(alert => (
<li key={alert} className="color-average">
{alert}
</li>
))}
</ul>
</Section>
<Section title="Atmospherics Alarms">
<ul>
{atmos.length === 0 && (
<li className="color-good">
Systems Nominal
</li>
)}
{atmos.map(alert => (
<li key={alert} className="color-average">
{alert}
</li>
))}
</ul>
</Section>
<Section title="Power Alarms">
<ul>
{power.length === 0 && (
<li className="color-good">
Systems Nominal
</li>
)}
{power.map(alert => (
<li key={alert} className="color-average">
{alert}
</li>
))}
</ul>
</Section>
</Fragment>
);
};

File diff suppressed because one or more lines are too long