[TGUI] Air Alarms + Central Atmos Control (#14620)

* [TGUI] Air Alarms + Central Atmos Control

* Mochi Tweaks
This commit is contained in:
AffectedArc07
2020-10-17 16:22:09 +01:00
committed by GitHub
parent 2731389080
commit d7e4e2cf5f
14 changed files with 812 additions and 591 deletions
+5 -5
View File
@@ -2,8 +2,8 @@
GLOBAL_DATUM_INIT(air_alarm_repository, /datum/repository/air_alarm, new())
/datum/repository/air_alarm/proc/air_alarm_data(var/list/monitored_alarms, var/refresh = 0, var/obj/machinery/alarm/passed_alarm)
var/alarms[0]
/datum/repository/air_alarm/proc/air_alarm_data(list/monitored_alarms, refresh = FALSE, obj/machinery/alarm/passed_alarm)
var/list/alarms = list()
var/datum/cache_entry/cache_entry = cache_data
if(!cache_entry)
@@ -16,20 +16,20 @@ GLOBAL_DATUM_INIT(air_alarm_repository, /datum/repository/air_alarm, new())
if(SSticker && SSticker.current_state < GAME_STATE_PLAYING && istype(passed_alarm)) // Generating the list for the first time as the game hasn't started - no need to run through the machines list everything every time
alarms = cache_entry.data // Don't deleate the list
if(is_station_contact(passed_alarm.z) && passed_alarm.remote_control) // Still need sanity checks
alarms[++alarms.len] = passed_alarm.get_nano_data_console()
alarms[++alarms.len] = passed_alarm.get_console_data()
else
for(var/obj/machinery/alarm/alarm in (monitored_alarms ? monitored_alarms : GLOB.air_alarms)) // Generating the whole list again is a bad habit but I can't be bothered to fix it right now
if(!monitored_alarms && !is_station_contact(alarm.z))
continue
if(!alarm.remote_control)
continue
alarms[++alarms.len] = alarm.get_nano_data_console()
alarms[++alarms.len] = alarm.get_console_data()
cache_entry.timestamp = world.time //+ 10 SECONDS
cache_entry.data = alarms
return alarms
/datum/repository/air_alarm/proc/update_cache(var/obj/machinery/alarm/alarm)
/datum/repository/air_alarm/proc/update_cache(obj/machinery/alarm/alarm)
return air_alarm_data(refresh = 1, passed_alarm = alarm)
#undef AIR_ALARM_DATA_CACHE_DURATION
+178 -197
View File
@@ -44,12 +44,6 @@
#define AALARM_PRESET_COLDROOM 3 // Kitchen coldroom
#define AALARM_PRESET_SERVER 4 // Server coldroom
#define AALARM_SCREEN_MAIN 1
#define AALARM_SCREEN_VENT 2
#define AALARM_SCREEN_SCRUB 3
#define AALARM_SCREEN_MODE 4
#define AALARM_SCREEN_SENSORS 5
#define AALARM_REPORT_TIMEOUT 100
#define RCON_NO 1
@@ -109,7 +103,6 @@
var/mode = AALARM_MODE_SCRUBBING
var/preset = AALARM_PRESET_HUMAN
var/screen = AALARM_SCREEN_MAIN
var/area_uid
var/area/alarm_area
var/danger_level = ATMOS_ALARM_NONE
@@ -377,7 +370,7 @@
if(ATMOS_ALARM_DANGER)
icon_state = "alarm1"
/obj/machinery/alarm/proc/register_env_machine(var/m_id, var/device_type)
/obj/machinery/alarm/proc/register_env_machine(m_id, device_type)
var/new_name
if(device_type=="AVP")
new_name = "[alarm_area.name] Vent Pump #[alarm_area.air_vent_names.len+1]"
@@ -407,7 +400,7 @@
frequency = new_frequency
radio_connection = SSradio.add_object(src, frequency, RADIO_TO_AIRALARM)
/obj/machinery/alarm/proc/send_signal(var/target, var/list/command)//sends signal 'command' to 'target'. Returns 0 if no radio connection, 1 otherwise
/obj/machinery/alarm/proc/send_signal(target, list/command)//sends signal 'command' to 'target'. Returns 0 if no radio connection, 1 otherwise
if(!radio_connection)
return 0
@@ -420,9 +413,7 @@
signal.data["sigtype"] = "command"
radio_connection.post_signal(src, signal, RADIO_FROM_AIRALARM)
// to_chat(world, text("Signal [] Broadcasted to []", command, target))
return 1
return TRUE
/obj/machinery/alarm/proc/apply_mode()
switch(mode)
@@ -573,10 +564,13 @@
///////////////
/obj/machinery/alarm/attack_ai(mob/user)
src.add_hiddenprint(user)
return ui_interact(user)
if(buildstage != 2)
return
/obj/machinery/alarm/attack_ghost(user as mob)
add_hiddenprint(user)
return tgui_interact(user)
/obj/machinery/alarm/attack_ghost(mob/user)
return interact(user)
/obj/machinery/alarm/attack_hand(mob/user)
@@ -593,7 +587,7 @@
wires.Interact(user)
if(!shorted)
ui_interact(user)
tgui_interact(user)
/obj/machinery/alarm/proc/ui_air_status()
var/turf/location = get_turf(src)
@@ -602,7 +596,7 @@
var/datum/gas_mixture/environment = location.return_air()
var/total = environment.oxygen + environment.nitrogen + environment.carbon_dioxide + environment.toxins
if(total==0)
if(total == 0)
return null
var/datum/tlv/cur_tlv
@@ -635,12 +629,12 @@
cur_tlv = TLV["temperature"]
var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature)
var/data[0]
var/list/data = list()
data["pressure"] = environment_pressure
data["temperature"] = environment.temperature
data["temperature_c"] = round(environment.temperature - T0C, 0.1)
var/percentages[0]
var/list/percentages = list()
percentages["oxygen"] = oxygen_percent
percentages["nitrogen"] = nitrogen_percent
percentages["co2"] = co2_percent
@@ -648,7 +642,7 @@
percentages["other"] = other_moles
data["contents"] = percentages
var/danger[0]
var/list/danger = list()
danger["pressure"] = pressure_dangerlevel
danger["temperature"] = temperature_dangerlevel
danger["oxygen"] = oxygen_dangerlevel
@@ -660,13 +654,12 @@
data["danger"] = danger
return data
/obj/machinery/alarm/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
/obj/machinery/alarm/proc/has_rcon_access(mob/user)
return user && (isAI(user) || allowed(user) || emagged || rcon_setting == RCON_YES)
var/list/href_list = state.href_list(user)
if(href_list)
data["remote_connection"] = href_list["remote_connection"]
data["remote_access"] = href_list["remote_access"]
// Intentional nulls here
/obj/machinery/alarm/tgui_data(mob/user)
var/list/data = list()
data["name"] = sanitize(name)
data["air"] = ui_air_status()
@@ -676,70 +669,70 @@
// Locked when:
// Not sent from atmos console AND
// Not silicon AND locked.
data["locked"] = !is_authenticated(user, href_list)
var/datum/tgui/active_ui = SStgui.get_open_ui(user, src, "main")
data["locked"] = !is_authenticated(user, active_ui)
data["rcon"] = rcon_setting
data["target_temp"] = target_temperature - T0C
data["atmos_alarm"] = alarm_area.atmosalm
data["emagged"] = emagged
data["modes"] = list(
AALARM_MODE_SCRUBBING = list("name"="Filtering", "desc"="Scrubs out contaminants"),\
AALARM_MODE_VENTING = list("name"="Draught", "desc"="Siphons out air while replacing"),\
AALARM_MODE_PANIC = list("name"="Panic Siphon","desc"="Siphons air out of the room quickly"),\
AALARM_MODE_REPLACEMENT = list("name"="Cycle", "desc"="Siphons air before replacing"),\
AALARM_MODE_SIPHON = list("name"="Siphon", "desc"="Siphons air out of the room"),\
AALARM_MODE_CONTAMINATED= list("name"="Contaminated","desc"="Scrubs out all contaminants quickly"),\
AALARM_MODE_REFILL = list("name"="Refill", "desc"="Triples vent output"),\
AALARM_MODE_OFF = list("name"="Off", "desc"="Shuts off vents and scrubbers"),\
AALARM_MODE_FLOOD = list("name"="Flood", "desc"="Shuts off scrubbers and opens vents", "emagonly" = 1)
AALARM_MODE_SCRUBBING = list("name"="Filtering", "desc"="Scrubs out contaminants", "id" = AALARM_MODE_SCRUBBING),\
AALARM_MODE_VENTING = list("name"="Draught", "desc"="Siphons out air while replacing", "id" = AALARM_MODE_VENTING),\
AALARM_MODE_PANIC = list("name"="Panic Siphon","desc"="Siphons air out of the room quickly", "id" = AALARM_MODE_PANIC),\
AALARM_MODE_REPLACEMENT = list("name"="Cycle", "desc"="Siphons air before replacing", "id" = AALARM_MODE_REPLACEMENT),\
AALARM_MODE_SIPHON = list("name"="Siphon", "desc"="Siphons air out of the room", "id" = AALARM_MODE_SIPHON),\
AALARM_MODE_CONTAMINATED= list("name"="Contaminated","desc"="Scrubs out all contaminants quickly", "id" = AALARM_MODE_CONTAMINATED),\
AALARM_MODE_REFILL = list("name"="Refill", "desc"="Triples vent output", "id" = AALARM_MODE_REFILL),\
AALARM_MODE_OFF = list("name"="Off", "desc"="Shuts off vents and scrubbers", "id" = AALARM_MODE_OFF),\
AALARM_MODE_FLOOD = list("name"="Flood", "desc"="Shuts off scrubbers and opens vents", "emagonly" = TRUE, "id" = AALARM_MODE_FLOOD)
)
data["mode"] = mode
data["presets"] = list(
AALARM_PRESET_HUMAN = list("name"="Human", "desc"="Checks for oxygen and nitrogen"),\
AALARM_PRESET_VOX = list("name"="Vox", "desc"="Checks for nitrogen only"),\
AALARM_PRESET_COLDROOM = list("name"="Coldroom", "desc"="For freezers"),\
AALARM_PRESET_SERVER = list("name"="Server Room", "desc"="For server rooms")
AALARM_PRESET_HUMAN = list("name"="Human", "desc"="Checks for oxygen and nitrogen", "id" = AALARM_PRESET_HUMAN),\
AALARM_PRESET_VOX = list("name"="Vox", "desc"="Checks for nitrogen only", "id" = AALARM_PRESET_VOX),\
AALARM_PRESET_COLDROOM = list("name"="Coldroom", "desc"="For freezers", "id" = AALARM_PRESET_COLDROOM),\
AALARM_PRESET_SERVER = list("name"="Server Room", "desc"="For server rooms", "id" = AALARM_PRESET_SERVER)
)
data["preset"] = preset
data["screen"] = screen
var/list/vents=list()
var/list/vents = list()
if(alarm_area.air_vent_names.len)
for(var/id_tag in alarm_area.air_vent_names)
var/vent_info[0]
var/list/vent_info = list()
var/long_name = alarm_area.air_vent_names[id_tag]
var/list/vent_data = alarm_area.air_vent_info[id_tag]
if(!vent_data)
continue
vent_info["id_tag"]=id_tag
vent_info["name"]=sanitize(long_name)
vent_info["id_tag"] = id_tag
vent_info["name"] = sanitize(long_name)
vent_info += vent_data
vents+=list(vent_info)
data["vents"]=vents
vents += list(vent_info)
data["vents"] = vents
var/list/scrubbers=list()
var/list/scrubbers = list()
if(alarm_area.air_scrub_names.len)
for(var/id_tag in alarm_area.air_scrub_names)
var/long_name = alarm_area.air_scrub_names[id_tag]
var/list/scrubber_data = alarm_area.air_scrub_info[id_tag]
if(!scrubber_data)
continue
scrubber_data["id_tag"]=id_tag
scrubber_data["name"]=sanitize(long_name)
scrubbers+=list(scrubber_data)
data["scrubbers"]=scrubbers
scrubber_data["id_tag"] = id_tag
scrubber_data["name"] = sanitize(long_name)
scrubbers += list(scrubber_data)
data["scrubbers"] = scrubbers
return data
/obj/machinery/alarm/proc/get_nano_data_console(mob/user)
var/data[0]
/obj/machinery/alarm/proc/get_console_data(mob/user)
var/list/data = list()
data["name"] = sanitize(name)
data["ref"] = "\ref[src]"
data["danger"] = max(danger_level, alarm_area.atmosalm)
var/area/Area = get_area(src)
data["area"] = sanitize(Area.name)
var/turf/pos = get_turf(src)
data["x"] = pos.x
data["y"] = pos.y
data["z"] = pos.z
var/area/A = get_area(src)
data["area"] = sanitize(A.name)
var/turf/T = get_turf(src)
data["x"] = T.x
data["y"] = T.y
data["z"] = T.z
return data
/obj/machinery/alarm/proc/generate_thresholds_menu()
@@ -747,9 +740,9 @@
var/list/thresholds = list()
var/list/gas_names = list(
"oxygen" = "O<sub>2</sub>",
"nitrogen" = "N<sub>2</sub>",
"carbon dioxide" = "CO<sub>2</sub>",
"oxygen" = "O2",
"nitrogen" = "N2",
"carbon dioxide" = "CO2",
"plasma" = "Toxin",
"other" = "Other")
for(var/g in gas_names)
@@ -776,28 +769,24 @@
return thresholds
/obj/machinery/alarm/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/alarm/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "air_alarm.tmpl", name, 570, 410, state = state)
ui = new(user, src, ui_key, "AirAlarm", name, 570, 410, master_ui, state)
ui.open()
ui.set_auto_update(1)
/obj/machinery/alarm/proc/is_authenticated(var/mob/user, href_list)
/obj/machinery/alarm/proc/is_authenticated(mob/user, datum/tgui/ui=null)
// Return true if they are connecting with a remote console
if(istype(ui?.master_ui?.src_object.type, /datum/tgui_module/atmos_control))
return TRUE
if(user.can_admin_interact())
return 1
else if(isAI(user) || isrobot(user) || emagged || is_auth_rcon(href_list))
return 1
return TRUE
else if(isAI(user) || isrobot(user) || emagged)
return TRUE
else
return !locked
/obj/machinery/alarm/proc/is_auth_rcon(href_list)
if(href_list && href_list["remote_connection"] && href_list["remote_access"])
return 1
else
return 0
/obj/machinery/alarm/CanUseTopic(var/mob/user, var/datum/topic_state/state, var/href_list = list())
/obj/machinery/alarm/tgui_status(mob/user, datum/tgui_state/state)
if(buildstage != 2)
return STATUS_CLOSE
@@ -807,146 +796,138 @@
. = shorted ? STATUS_DISABLED : STATUS_INTERACTIVE
if(. == STATUS_INTERACTIVE)
var/extra_href = state.href_list(usr)
// Prevent remote users from altering RCON settings or activating atmos alarms unless they already have access
if((href_list["atmos_alarm"] || href_list["rcon"]) && extra_href["remote_connection"] && !extra_href["remote_access"])
. = STATUS_UPDATE
return min(..(), .)
/obj/machinery/alarm/Topic(href, href_list, var/nowindow = 0, var/datum/topic_state/state)
if(..(href, href_list, nowindow, state))
return 1
var/state_href = state.href_list(usr)
if(href_list["rcon"])
var/attempted_rcon_setting = text2num(href_list["rcon"])
switch(attempted_rcon_setting)
if(RCON_NO)
rcon_setting = RCON_NO
if(RCON_AUTO)
rcon_setting = RCON_AUTO
if(RCON_YES)
rcon_setting = RCON_YES
return 1
// TODO: Refactor these utter pieces of garbage
/obj/machinery/alarm/tgui_act(action, list/params)
if(..())
return
add_fingerprint(usr)
if(href_list["command"])
if(!is_authenticated(usr, state_href))
return
. = TRUE
var/device_id = href_list["id_tag"]
switch(href_list["command"])
if( "power",
"adjust_external_pressure",
"set_external_pressure",
"checks",
"co2_scrub",
"tox_scrub",
"n2o_scrub",
"n2_scrub",
"o2_scrub",
"widenet",
"scrubbing",
"direction")
var/val
if(href_list["val"])
val=text2num(href_list["val"])
else
var/newval = input("Enter new value") as num|null
if(isnull(newval))
// Used for rcon auth
var/datum/tgui/active_ui = SStgui.get_open_ui(usr, src, "main")
switch(action)
if("set_rcon")
var/attempted_rcon_setting = text2num(params["rcon"])
switch(attempted_rcon_setting)
if(RCON_NO)
rcon_setting = RCON_NO
if(RCON_AUTO)
rcon_setting = RCON_AUTO
if(RCON_YES)
rcon_setting = RCON_YES
if("command")
if(!is_authenticated(usr, active_ui))
return
var/device_id = params["id_tag"]
switch(params["cmd"])
if ("power",
"adjust_external_pressure",
"set_external_pressure",
"checks",
"co2_scrub",
"tox_scrub",
"n2o_scrub",
"n2_scrub",
"o2_scrub",
"widenet",
"scrubbing",
"direction")
var/val
if(params["val"])
val=text2num(params["val"])
else
var/newval = input("Enter new value") as num|null
if(isnull(newval))
return
if(params["cmd"] == "set_external_pressure")
if(newval > 1000 + ONE_ATMOSPHERE)
newval = 1000 + ONE_ATMOSPHERE
if(newval < 0)
newval = 0
val = newval
// For those who read this: This radio BS is what makes air alarms take 10 years to update in the UI
send_signal(device_id, list(params["cmd"] = val))
waiting_on_device = device_id
if("set_threshold")
var/env = params["env"]
var/varname = params["var"]
var/datum/tlv/tlv = TLV[env]
var/newval = input("Enter [varname] for [env]", "Alarm triggers", tlv.vars[varname]) as num|null
if(isnull(newval) || ..()) // No setting if you walked away
return
if(href_list["command"]=="set_external_pressure")
if(newval>1000+ONE_ATMOSPHERE)
newval = 1000+ONE_ATMOSPHERE
if(newval<0)
newval = 0
val = newval
if(newval < 0)
tlv.vars[varname] = -1.0
else if(env == "temperature" && newval > 5000)
tlv.vars[varname] = 5000
else if(env == "pressure" && newval > 50 * ONE_ATMOSPHERE)
tlv.vars[varname] = 50 * ONE_ATMOSPHERE
else if(env != "temperature" && env != "pressure" && newval > 200)
tlv.vars[varname] = 200
else
newval = round(newval, 0.01)
tlv.vars[varname] = newval
send_signal(device_id, list(href_list["command"] = val ) )
waiting_on_device=device_id
if("atmos_alarm")
if(alarm_area.atmosalert(ATMOS_ALARM_DANGER, src))
post_alert(ATMOS_ALARM_DANGER)
alarmActivated = TRUE
update_icon()
if("set_threshold")
var/env = href_list["env"]
var/varname = href_list["var"]
var/datum/tlv/tlv = TLV[env]
var/newval = input("Enter [varname] for [env]", "Alarm triggers", tlv.vars[varname]) as num|null
if("atmos_reset")
if(alarm_area.atmosalert(ATMOS_ALARM_NONE, src, TRUE))
post_alert(ATMOS_ALARM_NONE)
alarmActivated = FALSE
update_icon()
if(isnull(newval) || ..(href, href_list, nowindow, state))
return
if(newval<0)
tlv.vars[varname] = -1.0
else if(env=="temperature" && newval>5000)
tlv.vars[varname] = 5000
else if(env=="pressure" && newval>50*ONE_ATMOSPHERE)
tlv.vars[varname] = 50*ONE_ATMOSPHERE
else if(env!="temperature" && env!="pressure" && newval>200)
tlv.vars[varname] = 200
else
newval = round(newval,0.01)
tlv.vars[varname] = newval
if("mode")
if(!is_authenticated(usr, active_ui))
return
if(href_list["screen"])
if(!is_authenticated(usr, state_href))
return
mode = text2num(params["mode"])
apply_mode()
screen = text2num(href_list["screen"])
return 1
if(href_list["atmos_alarm"])
if(alarm_area.atmosalert(ATMOS_ALARM_DANGER, src))
post_alert(ATMOS_ALARM_DANGER)
alarmActivated = 1
update_icon()
return 1
if("preset")
if(!is_authenticated(usr, active_ui))
return
if(href_list["atmos_reset"])
if(alarm_area.atmosalert(ATMOS_ALARM_NONE, src, TRUE))
post_alert(ATMOS_ALARM_NONE)
alarmActivated = 0
update_icon()
return 1
preset = text2num(params["preset"])
apply_preset()
if(href_list["mode"])
if(!is_authenticated(usr, state_href))
return
mode = text2num(href_list["mode"])
apply_mode()
return 1
if("temperature")
var/datum/tlv/selected = TLV["temperature"]
var/max_temperature = selected.max1 >= 0 ? min(selected.max1, MAX_TEMPERATURE) : max(selected.max1, MAX_TEMPERATURE)
var/min_temperature = max(selected.min1, MIN_TEMPERATURE)
var/max_temperature_c = max_temperature - T0C
var/min_temperature_c = min_temperature - T0C
var/input_temperature = input("What temperature would you like the system to maintain? (Capped between [min_temperature_c]C and [max_temperature_c]C)", "Thermostat Controls") as num|null
if(isnull(input_temperature) || ..()) // No temp setting if you walked away
return
input_temperature = input_temperature + T0C
if(input_temperature > max_temperature || input_temperature < min_temperature)
to_chat(usr, "<span class='warning'>Temperature must be between [min_temperature_c]C and [max_temperature_c]C</span>")
else
target_temperature = input_temperature
if(href_list["preset"])
if(!is_authenticated(usr, state_href))
return
preset = text2num(href_list["preset"])
apply_preset()
return 1
if(href_list["temperature"])
var/datum/tlv/selected = TLV["temperature"]
var/max_temperature = selected.max1 >= 0 ? min(selected.max1, MAX_TEMPERATURE) : max(selected.max1, MAX_TEMPERATURE)
var/min_temperature = max(selected.min1, MIN_TEMPERATURE)
var/max_temperature_c = max_temperature - T0C
var/min_temperature_c = min_temperature - T0C
var/input_temperature = input("What temperature would you like the system to maintain? (Capped between [min_temperature_c]C and [max_temperature_c]C)", "Thermostat Controls") as num|null
if(isnull(input_temperature) || ..(href, href_list, nowindow, state))
return
input_temperature = input_temperature + T0C
if(input_temperature > max_temperature || input_temperature < min_temperature)
to_chat(usr, "Temperature must be between [min_temperature_c]C and [max_temperature_c]C")
else
target_temperature = input_temperature
return 1
/obj/machinery/alarm/emag_act(mob/user)
if(!emagged)
src.emagged = 1
emagged = TRUE
if(user)
user.visible_message("<span class='warning'>Sparks fly out of the [src]!</span>", "<span class='notice'>You emag the [src], disabling its safeties.</span>")
playsound(src.loc, 'sound/effects/sparks4.ogg', 50, 1)
playsound(src.loc, 'sound/effects/sparks4.ogg', 50, TRUE)
return
/obj/machinery/alarm/attackby(obj/item/I, mob/user, params)
@@ -962,7 +943,7 @@
if(allowed(usr) && !wires.is_cut(WIRE_IDSCAN))
locked = !locked
to_chat(user, "<span class='notice'>You [ locked ? "lock" : "unlock"] the Air Alarm interface.</span>")
updateUsrDialog()
SStgui.update_uis(src)
else
to_chat(user, "<span class='warning'>Access denied.</span>")
return
+14 -23
View File
@@ -1,39 +1,30 @@
/obj/machinery/computer/atmoscontrol
name = "\improper Central Atmospherics Computer"
name = "\improper central atmospherics computer"
icon = 'icons/obj/computer.dmi'
icon_keyboard = "atmos_key"
icon_screen = "tank"
light_color = LIGHT_COLOR_GREEN
density = 1
anchored = 1.0
light_color = LIGHT_COLOR_CYAN
circuit = /obj/item/circuitboard/atmoscontrol
req_access = list(ACCESS_ATMOSPHERICS)
var/list/monitored_alarm_ids = null
var/datum/nano_module/atmos_control/atmos_control
var/datum/tgui_module/atmos_control/atmos_control
/obj/machinery/computer/atmoscontrol/Initialize()
. = ..()
atmos_control = new(src)
/obj/machinery/computer/atmoscontrol/laptop
name = "atmospherics laptop"
desc = "Cheap Nanotrasen laptop."
icon_state = "medlaptop"
density = 0
density = FALSE
/obj/machinery/computer/atmoscontrol/attack_ai(var/mob/user as mob)
ui_interact(user)
/obj/machinery/computer/atmoscontrol/attack_ai(mob/user)
tgui_interact(user)
/obj/machinery/computer/atmoscontrol/attack_hand(mob/user)
if(..())
return 1
ui_interact(user)
return
tgui_interact(user)
/obj/machinery/computer/atmoscontrol/emag_act(mob/user)
if(!emagged)
user.visible_message("<span class='warning'>\The [user] does something \the [src], causing the screen to flash!</span>",\
"<span class='warning'>You cause the screen to flash as you gain full control.</span>",\
"You hear an electronic warble.")
atmos_control.emagged = 1
return 1
/obj/machinery/computer/atmoscontrol/ui_interact(var/mob/user)
if(!atmos_control)
atmos_control = new(src, req_access, req_one_access, monitored_alarm_ids)
atmos_control.ui_interact(user)
/obj/machinery/computer/atmoscontrol/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
atmos_control.tgui_interact(user, ui_key, ui, force_open)
@@ -1,7 +1,6 @@
/mob/living/silicon
var/register_alarms = 1
var/datum/nano_module/alarm_monitor/all/alarm_monitor
var/datum/nano_module/atmos_control/atmos_control
var/register_alarms = TRUE
var/datum/tgui_module/atmos_control/atmos_control
var/datum/tgui_module/crew_monitor/crew_monitor
var/datum/nano_module/law_manager/law_manager
var/datum/tgui_module/power_monitor/digital/power_monitor
@@ -41,7 +40,7 @@
set category = "Subsystems"
set name = "Atmospherics Control"
atmos_control.ui_interact(usr, state = GLOB.self_state)
atmos_control.tgui_interact(usr, state = GLOB.tgui_self_state)
/********************
* Crew Monitor *
@@ -1,78 +0,0 @@
/datum/nano_module/atmos_control
name = "Atmospherics Control"
var/obj/access = new()
var/emagged = 0
var/ui_ref
var/list/monitored_alarms = null
/datum/nano_module/atmos_control/New(atmos_computer, req_access, req_one_access, monitored_alarm_ids)
..()
access.req_access = req_access
access.req_one_access = req_one_access
if(monitored_alarm_ids)
for(var/obj/machinery/alarm/alarm in GLOB.machines)
if(alarm.alarm_id && (alarm.alarm_id in monitored_alarm_ids))
monitored_alarms += alarm
// machines may not yet be ordered at this point
monitored_alarms = dd_sortedObjectList(monitored_alarms)
/datum/nano_module/atmos_control/Topic(href, href_list)
if(..())
return 1
if(href_list["alarm"])
if(ui_ref)
var/obj/machinery/alarm/alarm = locate(href_list["alarm"]) in (monitored_alarms ? monitored_alarms : GLOB.machines)
if(alarm)
var/datum/topic_state/air_alarm/TS = generate_state(alarm)
alarm.ui_interact(usr, master_ui = ui_ref, state = TS)
/datum/nano_module/atmos_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/master_ui = null, 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, "atmos_control.tmpl", src.name, 900, 800, state = state)
ui.add_template("mapContent", "atmos_control_map_content.tmpl")
ui.add_template("mapHeader", "atmos_control_map_header.tmpl")
// Send nanomaps
var/datum/asset/nanomaps = get_asset_datum(/datum/asset/simple/nanomaps)
nanomaps.send(user)
ui.set_show_map(1)
ui.open()
ui.set_auto_update(1)
ui_ref = ui
/datum/nano_module/atmos_control/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["alarms"] = GLOB.air_alarm_repository.air_alarm_data(monitored_alarms)
return data
/datum/nano_module/atmos_control/proc/generate_state(air_alarm)
var/datum/topic_state/air_alarm/state = new()
state.atmos_control = src
state.air_alarm = air_alarm
return state
/datum/topic_state/air_alarm
var/datum/nano_module/atmos_control/atmos_control = null
var/obj/machinery/alarm/air_alarm = null
/datum/topic_state/air_alarm/can_use_topic(var/src_object, var/mob/user)
if(!isAI(user) && !in_range(atmos_control.nano_host(), user))
return STATUS_CLOSE
if(has_access(user))
return STATUS_INTERACTIVE
return STATUS_UPDATE
/datum/topic_state/air_alarm/href_list(var/mob/user)
var/list/extra_href = list()
extra_href["remote_connection"] = TRUE
extra_href["remote_access"] = has_access(user)
return extra_href
/datum/topic_state/air_alarm/proc/has_access(var/mob/user)
return user && (isAI(user) || atmos_control.access.allowed(user) || atmos_control.emagged || air_alarm.rcon_setting == RCON_YES || air_alarm.emagged || (air_alarm.alarm_area.atmosalm && air_alarm.rcon_setting == RCON_AUTO))
@@ -0,0 +1,29 @@
/datum/tgui_module/atmos_control
name = "Atmospherics Control"
/datum/tgui_module/atmos_control/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return
switch(action)
if("open_alarm")
var/obj/machinery/alarm/alarm = locate(params["aref"]) in GLOB.air_alarms
if(alarm)
alarm.tgui_interact(usr, master_ui = ui, state = GLOB.tgui_always_state) // ALWAYS is intentional here, as the master_ui pass will prevent fuckery
/datum/tgui_module/atmos_control/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "AtmosControl", name, 800, 600, master_ui, state)
// Send nanomaps
var/datum/asset/nanomaps = get_asset_datum(/datum/asset/simple/nanomaps)
nanomaps.send(user)
ui.open()
/datum/tgui_module/atmos_control/tgui_data(mob/user)
var/list/data = list()
data["alarms"] = GLOB.air_alarm_repository.air_alarm_data(GLOB.air_alarms)
return data
-254
View File
@@ -1,254 +0,0 @@
<!--
Title: Air Alarm UI
Used In File(s): /code/game/machinery/alarm.dm
-->
<!--
#define AALARM_MODE_SCRUBBING 1
#define AALARM_MODE_REPLACEMENT 2 //like scrubbing, but faster.
#define AALARM_MODE_PANIC 3 //constantly sucks all air
#define AALARM_MODE_CYCLE 4 //sucks off all air, then refill and switches to scrubbing
#define AALARM_MODE_FILL 5 //emergency fill
#define AALARM_MODE_OFF 6 //Shuts it all down.
#define AALARM_SCREEN_MAIN 1
#define AALARM_SCREEN_VENT 2
#define AALARM_SCREEN_SCRUB 3
#define AALARM_SCREEN_MODE 4
#define AALARM_SCREEN_SENSORS 5
-->
<h3>{{:data.name}}</h3>
{{if !data.air}}
<div class="notice">Unable to acquire air sample.</div>
{{else}}
<div class="statusDisplay">
<div class="line">
<div class="statusLabel">Pressure:</div>
{{:helper.string("<div class='statusValue {0}'>{1} kPa</div>",helper.dangerToClass(data.air.danger.pressure),helper.smoothRound(data.air.pressure,4))}}
<div class="statusValue" style="margin-left:5px;">
{{if !data.locked}}
{{if data.mode == 3}}
{{:helper.link("DEACTIVATE PANIC SYPHON",null,{"mode" : 1},null,'linkOn')}}
{{else}}
{{:helper.link("ACTIVATE PANIC SYPHON",null,{"mode" : 3},null,'red')}}
{{/if}}
{{/if}}
</div>
</div>
<div class="line">
<div class="statusLabel">Oxygen:</div>
{{:helper.displayBar(data.air.contents.oxygen, 0, 100, helper.dangerToClass(data.air.danger.oxygen))}}
{{:helper.string("<div class='statusValue {0}'>{1}%</div>",helper.dangerToClass(data.air.danger.oxygen),helper.smoothRound(data.air.contents.oxygen))}}
</div>
<div class="line">
<div class="statusLabel">Nitrogen:</div>
{{:helper.displayBar(data.air.contents.nitrogen, 0, 100, helper.dangerToClass(data.air.danger.nitrogen))}}
{{:helper.string("<div class='statusValue {0}'>{1}%</div>",helper.dangerToClass(data.air.danger.nitrogen),helper.smoothRound(data.air.contents.nitrogen,0))}}
</div>
<div class="line">
<div class="statusLabel">Carbon Dioxide:</div>
{{:helper.displayBar(data.air.contents.co2, 0, 100, helper.dangerToClass(data.air.danger.co2))}}
{{:helper.string("<div class='statusValue {0}'>{1}%</div>",helper.dangerToClass(data.air.danger.co2),helper.smoothRound(data.air.contents.co2,0))}}
</div>
<div class="line">
<div class="statusLabel">Toxins:</div>
{{:helper.displayBar(data.air.contents.plasma, 0, 100, helper.dangerToClass(data.air.danger.plasma))}}
{{:helper.string("<div class='statusValue {0}'>{1}%</div>",helper.dangerToClass(data.air.danger.plasma),helper.smoothRound(data.air.contents.plasma,0))}}
</div>
{{if data.air.danger.other>0}}
<div class="line">
<div class="statusLabel">Other:</div>
{{:helper.displayBar(data.air.contents.other, 0, 100, helper.dangerToClass(data.air.danger.other))}}
{{:helper.string("<div class='statusValue {0}'>{1}%</div>",helper.dangerToClass(data.air.danger.other),helper.smoothRound(data.air.contents.other,0))}}
</div>
{{/if}}
<div class="line">
<div class="statusLabel">
Temperature:
</div>
{{:helper.string("<div class='statusValue {0}'>{1}&deg;K ({2}&deg;C)</div>",helper.dangerToClass(data.air.danger.temperature),helper.smoothRound(data.air.temperature,2),helper.smoothRound(data.air.temperature_c,2))}}
</div>
<div class="line">
<div class="statusLabel">Local Status:</div>
{{if data.air.danger.overall == 0}}
{{if data.atmos_alarm}}
<div class="average">Caution: Atmos alert in area</div>
{{else}}
<div class="good">Optimal</div>
{{/if}}
{{else data.air.danger.overall == 1}}
<div class="average">Caution</div>
{{else}}
<div class="notice">DANGER: Internals Required</div>
{{/if}}
{{if !data.locked}}
{{if data.alarmActivated}}
{{:helper.link('Reset Alarm',null,{'atmos_reset':1},null,'linkOn')}}
{{else}}
{{:helper.link('Activate Alarm',null,{'atmos_alarm':1},null)}}
{{/if}}
{{/if}}
</div>
<div class="line">
<!--
#define RCON_NO 1
#define RCON_AUTO 2
#define RCON_YES 3
-->
<div class="statusLabel">Remote Control:</div>
{{:helper.link('Off', null, {'rcon' : 1}, data.remote_connection && !data.remote_access ? (data.rcon == 1 ? '' : 'disabled') : null, data.rcon == 1 ? 'selected' : null)}}
{{:helper.link('Auto', null, {'rcon' : 2}, data.remote_connection && !data.remote_access ? (data.rcon == 2 ? '' : 'disabled') : null, data.rcon == 2 ? 'selected' : null)}}
{{:helper.link('On', null, {'rcon' : 3}, data.remote_connection && !data.remote_access ? (data.rcon == 3 ? '' : 'disabled') : null, data.rcon == 3 ? 'selected' : null)}}
</div>
<div class="line">
<div class="statusLabel">Thermostat:</div>
{{:helper.link(data.target_temp+" C", 'thermometer', {'temperature': 1})}}
</div>
</div>
{{/if}}
{{if data.locked}}
<div class="notice">Swipe card to unlock.</div>
{{else}}
<div class="notice">Remember to lock with ID card after use.</div>
<div class="item">
<div class="itemLabel">Screen:</div>
<div class="itemContents">
{{:helper.link('Main', 'gear',{'screen':1},(data.screen==1)?'linkOn':'')}}
{{:helper.link('Vents', 'gear',{'screen':2},(data.screen==2)?'linkOn':'')}}
{{:helper.link('Scrubbers', 'gear',{'screen':3},(data.screen==3)?'linkOn':'')}}
{{:helper.link('Mode', 'gear',{'screen':4},(data.screen==4)?'linkOn':'')}}
{{:helper.link('Thresholds','gear',{'screen':5},(data.screen==5)?'linkOn':'')}}
</div>
</div>
<!-- VENTS -->
{{if data.screen == 2}}
<h3>Vent Pump Settings</h3>
{{for data.vents}}
<div class="statusDisplay">
<div class="line">
<b>{{>value.name}}:</b>
</div>
<div class="line">
<div class="statusLabel">Operating:</div>
<div class="statusValue">
{{:helper.link(value.power ? 'On':'Off','power-off',{'id_tag':value.id_tag,'command':'power','val':value.power?0:1},null)}}
{{if value.direction=="siphon"}}
{{:helper.link('Siphoning','arrow-circle-down',{'id_tag':value.id_tag,'command':'direction','val':'1'})}}
{{else}}
{{:helper.link('Blowing','arrow-up',{'id_tag':value.id_tag,'command':'direction','val':'0'})}}
{{/if}}
</div>
</div>
<div class="line">
<div class="statusLabel">Pressure checks:</div>
<div class="statusValue">
{{:helper.link('External', 'power-off',{'id_tag':value.id_tag,'command':'checks','val':1},null,(value.checks == 1 ?'linkOn':''))}}
{{:helper.link('Internal', 'power-off',{'id_tag':value.id_tag,'command':'checks','val':2},null,(value.checks == 2 ?'linkOn':''))}}
</div>
</div>
<div class="line">
<div class="statusLabel">External pressure target:</div>
<div class="statusValue">
{{:helper.smoothRound(value.external,4)}} kPa
</div>
{{:helper.link('Set','gear',{'id_tag':value.id_tag,'command':'set_external_pressure'})}}
{{:helper.link('Reset','refresh',{'id_tag':value.id_tag,'command':'set_external_pressure','val':101.325},null,'linkOn')}}
</div>
</div>
{{empty}}
<i>No vent pumps located in this area.</i>
{{/for}}
<!-- SCRUBBERS -->
{{else data.screen == 3}}
<h3>Scrubbers</h3>
{{for data.scrubbers}}
<div class="statusDisplay">
<div class="line">
<b>{{>value.name}}:</b>
</div>
<div class="line">
<div class="statusLabel">Operating:</div>
<div class="statusValue">
{{:helper.link(value.power ? 'On':'Off','power-off',{'id_tag':value.id_tag,'command':'power','val':value.power?0:1},null)}}
</div>
</div>
<div class="line">
<div class="statusLabel">Type:</div>
<div class="statusValue">
{{if value.scrubbing==0}}
{{:helper.link('Siphoning','arrow-circle-down',{'id_tag':value.id_tag,'command':'scrubbing','val':1},null,'red')}}
{{else}}
{{:helper.link('Scrubbing','exchange',{'id_tag':value.id_tag,'command':'scrubbing','val':0},null,'linkOn')}}
{{/if}}
</div>
</div>
<div class="line">
<div class="statusLabel">Scrub Range:</div>
<div class="statusValue">
{{:helper.link(value.widenet ? 'Extended' : 'Normal', null, { 'id_tag' : value.id_tag, 'command' : 'widenet', 'val' : value.widenet ? 0 : 1}, null, value.widenet ? 'selected' : null)}}
</div>
</div>
{{if value.scrubbing==1}}
<div class="line">
<div class="statusLabel">Filtering:</div>
<div class="statusValue">
{{:helper.link('CO<sub>2</sub>',null,{'id_tag':value.id_tag,'command':'co2_scrub','val':(value.filter_co2==0?1:0)},null,(value.filter_co2?'linkOn':''))}}
{{:helper.link('Plasma', null,{'id_tag':value.id_tag,'command':'tox_scrub','val':(value.filter_toxins==0?1:0)},null,(value.filter_toxins?'linkOn':''))}}
{{:helper.link('N<sub>2</sub>O',null,{'id_tag':value.id_tag,'command':'n2o_scrub','val':(value.filter_n2o==0?1:0)},null,(value.filter_n2o?'linkOn':''))}}
{{:helper.link('O<sub>2</sub>', null,{'id_tag':value.id_tag,'command':'o2_scrub', 'val':(value.filter_o2 ==0?1:0)},null,(value.filter_o2 ?'linkOn':''))}}
{{:helper.link('N<sub>2</sub>', null,{'id_tag':value.id_tag,'command':'n2_scrub', 'val':(value.filter_n2 ==0?1:0)},null,(value.filter_n2 ?'linkOn':''))}}
</div>
</div>
{{/if}}
</div>
{{empty}}
<i>No scrubbers located in this area.</i>
{{/for}}
<!-- MODES -->
{{else data.screen == 4}}
<h3>System Mode</h3>
<div class="statusDisplay">
{{for data.modes}}
{{if !value.emagonly || value.emagonly && data.emagged}}
<div class="line">
<div class="statusLabel">{{:helper.link(value.name,'gear',{'mode':index+1},null,(index+1==data.mode?'linkOn':value.emagonly ? 'redButton' : ''))}}</div>
<div class="statusValue">
{{:value.desc}}
</div>
</div>
{{/if}}
{{/for}}
</div>
<h3>System Preset</h3>
<div class="notice">After making a selection, the system will automatically cycle in order to remove contaminants.</div>
<div class="statusDisplay">
{{for data.presets}}
<div class="line">
<div class="statusLabel">{{:helper.link(value.name,'gear',{'preset':index+1},null,(index+1==data.preset?'linkOn':''))}}</div>
<div class="statusValue">
{{:value.desc}}
</div>
</div>
{{/for}}
</div>
<!-- SENSORS -->
{{else data.screen == 5}}
<h3>Alarm Threshold</h3>
Partial pressure for gases.
<table class='fixed'>
<tr>
<td></td><td><span class='bad'>min2</span></td><td><span class='average'>min1</span></td><td><span class='average'>max1</span></td><td><span class='bad'>max2</span></td>
</tr>
{{for data.thresholds}}
<tr>
<td>{{:value.name}}</td>
{{for value.settings :selectedItem:SelectedNull}}
<td>
{{:helper.link(selectedItem.selected >= 0 ? helper.round(selectedItem.selected*100)/100 : "Off", null, { 'command' : 'set_threshold', 'env' : selectedItem.env, 'var' : selectedItem.val })}}
</td>
{{/for}}
</tr>
{{/for}}
<table>
{{/if}}
{{/if}}
-10
View File
@@ -1,10 +0,0 @@
{{:helper.link('Show Tracker Map', 'thumb-tack', {'showMap' : 1})}}
<h3>Atmospherics Control</h3>
<div class='item'>
{{for data.alarms}}
<div class="line">
{{:helper.string("<div class='statusValue {0}'>{1}</div>", helper.dangerToClass(value.danger), value.name)}}
{{:helper.link("Access", "gear", {"alarm" : value.ref}, null, "floatRight")}}
</div>
{{/for}}
</div>
@@ -1,9 +0,0 @@
{{for data.alarms}}
{{if value.z == 1}}
<div class="linkActive mapIcon mapIcon16 icon-airalarm {{:helper.dangerToClass(value.danger)}}" style="left: {{:(value.x)}}px; bottom: {{:(value.y - 1)}}px;" unselectable="on" data-href="{{:NanoUtility.generateHref({"alarm":value.ref, "showMap":0})}}">
<div class="tooltip hidden">
{{:value.name}} ({{:helper.dangerToSpan(value.danger)}}, {{:value.area}}: {{:value.x}}, {{:value.y}})
</div>
</div>
{{/if}}
{{/for}}
@@ -1,8 +0,0 @@
{{:helper.link('Show Detail List', 'file-text', {'showMap' : 0})}}
<div style="float: right; width: 240px;">
<span style="float: left;">Zoom Level:&nbsp;</span>
<div unselectable="on" class="link zoomLink" data-zoom-level="2">x1</div>
<div unselectable="on" class="link zoomLink" data-zoom-level="4">x2</div>
<div unselectable="on" class="link zoomLink" data-zoom-level="8">x4</div>
<div unselectable="on" class="link zoomLink" data-zoom-level="16">x8</div>
</div>
+1 -1
View File
@@ -2098,7 +2098,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\atmos_control.dm"
#include "code\modules\nano\modules\human_appearance.dm"
#include "code\modules\nano\modules\law_manager.dm"
#include "code\modules\nano\modules\nano_module.dm"
@@ -2440,6 +2439,7 @@
#include "code\modules\tgui\states.dm"
#include "code\modules\tgui\tgui.dm"
#include "code\modules\tgui\modules\_base.dm"
#include "code\modules\tgui\modules\atmos_control.dm"
#include "code\modules\tgui\modules\crew_monitor.dm"
#include "code\modules\tgui\modules\ert_manager.dm"
#include "code\modules\tgui\modules\power_monitor.dm"
+437
View File
@@ -0,0 +1,437 @@
import { Fragment } from "inferno";
import { useBackend, useLocalState } from "../backend";
import { Button, LabeledList, Box, AnimatedNumber, Section, ProgressBar, Icon, Tabs, Table } from "../components";
import { Window } from "../layouts";
import { InterfaceLockNoticeBox } from "./common/InterfaceLockNoticeBox";
export const AirAlarm = (props, context) => {
const { act, data } = useBackend(context);
const {
locked,
} = data;
// Bail straight away if there is no air
return (
<Window resizable>
<Window.Content scrollable>
<AirStatus />
<InterfaceLockNoticeBox />
{!locked && (
<Fragment>
<AirAlarmTabs />
<AirAlarmUnlockedContent />
</Fragment>
)}
</Window.Content>
</Window>
);
};
const Danger2Colour = danger => {
if (danger === 0) {
return "green";
}
if (danger === 1) {
return "orange";
}
return "red";
};
const AirStatus = (props, context) => {
const { act, data } = useBackend(context);
const {
air,
mode,
atmos_alarm,
locked,
alarmActivated,
rcon,
} = data;
let areaStatus;
if (air.danger.overall === 0) {
if (atmos_alarm === 0) {
areaStatus = "Optimal";
} else {
areaStatus = "Caution: Atmos alert in area";
}
} else if (air.danger.overall === 1) {
areaStatus = "Caution";
} else {
areaStatus = "DANGER: Internals Required";
}
return (
<Section title="Air Status">
{air ? (
<LabeledList>
<LabeledList.Item label="Pressure">
<Box color={Danger2Colour(air.danger.pressure)}>
<AnimatedNumber value={air.pressure} /> kPa
{!locked && (
<Fragment>
&nbsp;
<Button
content={mode === 3 ? "Deactivate Panic Siphon" : "Activate Panic Siphon"}
selected={mode === 3}
icon="exclamation-triangle"
onClick={
() => act('mode', { mode: (mode === 3 ? 1 : 3) })
} />
</Fragment>
)}
</Box>
</LabeledList.Item>
<LabeledList.Item label="Oxygen">
<ProgressBar
value={air.contents.oxygen / 100}
color={Danger2Colour(air.danger.oxygen)} />
</LabeledList.Item>
<LabeledList.Item label="Nitrogen">
<ProgressBar
value={air.contents.nitrogen / 100}
color={Danger2Colour(air.danger.nitrogen)} />
</LabeledList.Item>
<LabeledList.Item label="Carbon Dioxide">
<ProgressBar
value={air.contents.co2 / 100}
color={Danger2Colour(air.danger.co2)} />
</LabeledList.Item>
<LabeledList.Item label="Toxins">
<ProgressBar
value={air.contents.plasma / 100}
color={Danger2Colour(air.danger.plasma)} />
</LabeledList.Item>
{air.contents.other > 0 && (
<LabeledList.Item label="Other">
<ProgressBar
value={air.contents.other / 100}
color={Danger2Colour(air.danger.other)} />
</LabeledList.Item>
)}
<LabeledList.Item label="Temperature">
<Box color={Danger2Colour(air.danger.temperature)}>
<AnimatedNumber value={air.temperature} /> K / <AnimatedNumber value={air.temperature_c} /> C&nbsp;
<Button
icon="thermometer-full"
content={air.temperature_c + " C"}
onClick={
() => act('temperature')
} />
</Box>
</LabeledList.Item>
<LabeledList.Item label="Local Status">
<Box color={Danger2Colour(air.danger.overall)}>
{areaStatus}
{!locked && (
<Fragment>
&nbsp;
<Button
content={alarmActivated ? "Reset Alarm" : "Activate Alarm"}
selected={alarmActivated}
onClick={
() => act(alarmActivated ? 'atmos_reset' : 'atmos_alarm')
} />
</Fragment>
)}
</Box>
</LabeledList.Item>
<LabeledList.Item label="Remote Control Settings">
<Button
content="Off"
selected={rcon === 1}
onClick={
() => act('set_rcon', { rcon: 1 })
} />
<Button
content="Auto"
selected={rcon === 2}
onClick={
() => act('set_rcon', { rcon: 2 })
} />
<Button
content="On"
selected={rcon === 3}
onClick={
() => act('set_rcon', { rcon: 3 })
} />
</LabeledList.Item>
</LabeledList>
) : (
<Box>
Unable to acquire air sample!
</Box>
)}
</Section>
);
};
const AirAlarmTabs = (props, context) => {
const [tabIndex, setTabIndex] = useLocalState(context, 'tabIndex', 0);
return (
<Tabs>
<Tabs.Tab
key="Vents"
selected={0 === tabIndex}
onClick={() => setTabIndex(0)}>
<Icon name="sign-out-alt" /> Vent Control
</Tabs.Tab>
<Tabs.Tab
key="Scrubbers"
selected={1 === tabIndex}
onClick={() => setTabIndex(1)}>
<Icon name="sign-in-alt" /> Scrubber Control
</Tabs.Tab>
<Tabs.Tab
key="Mode"
selected={2 === tabIndex}
onClick={() => setTabIndex(2)}>
<Icon name="cog" /> Mode
</Tabs.Tab>
<Tabs.Tab
key="Thresholds"
selected={3 === tabIndex}
onClick={() => setTabIndex(3)}>
<Icon name="tachometer-alt" /> Thresholds
</Tabs.Tab>
</Tabs>
);
};
const AirAlarmUnlockedContent = (props, context) => {
const [tabIndex, setTabIndex] = useLocalState(context, 'tabIndex', 0);
switch (tabIndex) {
case 0:
return <AirAlarmVentsView />;
case 1:
return <AirAlarmScrubbersView />;
case 2:
return <AirAlarmModesView />;
case 3:
return <AirAlarmThresholdsView />;
default:
return "WE SHOULDN'T BE HERE!";
}
};
const AirAlarmVentsView = (props, context) => {
const { act, data } = useBackend(context);
const { vents } = data;
return (
vents.map(v => (
<Section title={v.name} key={v.name}>
<LabeledList>
<LabeledList.Item label="Status">
<Button
content={v.power ? "On" : "Off"}
selected={v.power}
icon="power-off"
onClick={
() => act('command', { cmd: 'power', val: (v.power === 1 ? 0 : 1), id_tag: v.id_tag })
} />
<Button
content={v.direction === "release" ? "Blowing" : "Siphoning"}
icon={v.direction === "release" ? "sign-out-alt" : "sign-in-alt"}
onClick={
() => act('command', { cmd: 'direction', val: (v.direction === "release" ? 0 : 1), id_tag: v.id_tag })
} />
</LabeledList.Item>
<LabeledList.Item label="Pressure Checks">
<Button
content="Internal"
selected={v.checks === 1}
onClick={
() => act('command', { cmd: 'checks', val: 1, id_tag: v.id_tag })
} />
<Button
content="External"
selected={v.checks === 2}
onClick={
() => act('command', { cmd: 'checks', val: 2, id_tag: v.id_tag })
} />
</LabeledList.Item>
<LabeledList.Item label="External Pressure Target">
<AnimatedNumber value={v.external} /> kPa&nbsp;
<Button
content="Set"
icon="cog"
onClick={
() => act('command', { cmd: 'set_external_pressure', id_tag: v.id_tag })
} />
<Button
content="Reset"
icon="redo-alt"
onClick={
() => act('command', { cmd: 'set_external_pressure', val: 101.325, id_tag: v.id_tag })
} />
</LabeledList.Item>
</LabeledList>
</Section>
))
);
};
const AirAlarmScrubbersView = (props, context) => {
const { act, data } = useBackend(context);
const { scrubbers } = data;
return (
scrubbers.map(s => (
<Section title={s.name} key={s.name}>
<LabeledList>
<LabeledList.Item label="Status">
<Button
content={s.power ? "On" : "Off"}
selected={s.power}
icon="power-off"
onClick={
() => act('command', { cmd: 'power', val: (s.power === 1 ? 0 : 1), id_tag: s.id_tag })
} />
<Button
content={s.scrubbing === 0 ? "Siphoning" : "Scrubbing"}
icon={s.scrubbing === 0 ? "sign-in-alt" : "filter"}
onClick={
() => act('command', { cmd: 'scrubbing', val: (s.scrubbing === 0 ? 1 : 0), id_tag: s.id_tag })
} />
</LabeledList.Item>
<LabeledList.Item label="Range">
<Button
content={s.widenet ? "Extended" : "Normal"}
selected={s.widenet}
icon="expand-arrows-alt"
onClick={
() => act('command', { cmd: 'widenet', val: (s.widenet === 0 ? 1 : 0), id_tag: s.id_tag })
} />
</LabeledList.Item>
<LabeledList.Item label="Filtering">
<Button
content="Cargon Dioxide"
selected={s.filter_co2}
onClick={
() => act('command', { cmd: 'co2_scrub', val: (s.filter_co2 === 0 ? 1 : 0), id_tag: s.id_tag })
} />
<Button
content="Plasma"
selected={s.filter_toxins}
onClick={
() => act('command', { cmd: 'tox_scrub', val: (s.filter_toxins === 0 ? 1 : 0), id_tag: s.id_tag })
} />
<Button
content="Nitrous Oxide"
selected={s.filter_n2o}
onClick={
() => act('command', { cmd: 'n2o_scrub', val: (s.filter_n2o === 0 ? 1 : 0), id_tag: s.id_tag })
} />
<Button
content="Oxygen"
selected={s.filter_o2}
onClick={
() => act('command', { cmd: 'o2_scrub', val: (s.filter_o2 === 0 ? 1 : 0), id_tag: s.id_tag })
} />
<Button
content="Nitrogen"
selected={s.filter_n2}
onClick={
() => act('command', { cmd: 'n2_scrub', val: (s.filter_n2 === 0 ? 1 : 0), id_tag: s.id_tag })
} />
</LabeledList.Item>
</LabeledList>
</Section>
))
);
};
const AirAlarmModesView = (props, context) => {
const { act, data } = useBackend(context);
const {
modes,
presets,
emagged,
mode,
preset,
} = data;
return (
<Fragment>
<Section title="System Mode">
<Table>
{modes.map(m => (
(!m.emagonly || m.emagonly && !!emagged) && (
<Table.Row key={m.name}>
<Table.Cell textAlign="right" width={1}>
<Button content={m.name} icon="cog" selected={m.id === mode} onClick={
() => act('mode', { mode: m.id })
} />
</Table.Cell>
<Table.Cell>
{m.desc}
</Table.Cell>
</Table.Row>
)
))}
</Table>
</Section>
<Section title="System Presets">
<Box italic>
After making a selection, the system will automatically cycle in order to remove contaminants.
</Box>
<Table mt={1}>
{presets.map(p => (
<Table.Row key={p.name}>
<Table.Cell textAlign="right" width={1}>
<Button content={p.name} icon="cog" selected={p.id === preset} onClick={
() => act('preset', { preset: p.id })
} />
</Table.Cell>
<Table.Cell>
{p.desc}
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
</Fragment>
);
};
const AirAlarmThresholdsView = (props, context) => {
const { act, data } = useBackend(context);
const {
thresholds,
} = data;
return (
<Section title="Alarm Thresholds">
<Table>
<Table.Row header>
<Table.Cell width="20%">
Value
</Table.Cell>
<Table.Cell color="red" width="20%">
Danger Min
</Table.Cell>
<Table.Cell color="orange" width="20%">
Warning Min
</Table.Cell>
<Table.Cell color="orange" width="20%">
Warning Max
</Table.Cell>
<Table.Cell color="red" width="20%">
Danger Max
</Table.Cell>
</Table.Row>
{thresholds.map(t => (
<Table.Row key={t.name}>
<Table.Cell>
{t.name}
</Table.Cell>
{t.settings.map(s => (
<Table.Cell key={s.val}>
<Button content={s.selected === -1 ? "Off" : s.selected} onClick={
() => act('command', { cmd: 'set_threshold', env: s.env, var: s.val })
} />
</Table.Cell>
))}
</Table.Row>
))}
</Table>
</Section>
);
};
@@ -0,0 +1,143 @@
import { useBackend, useLocalState } from "../backend";
import { Box, Button, Icon, NanoMap, Table, Tabs } from "../components";
import { TableCell } from '../components/Table';
import { Window } from "../layouts";
const getStatus = level => {
if (level === 0) {
return (
<Box color="green">
Good
</Box>
);
}
if (level === 1) {
return (
<Box color="orange" bold>
Warning
</Box>
);
}
if (level === 2) {
return (
<Box color="red" bold>
DANGER
</Box>
);
}
};
const getStatusColour = level => {
if (level === 0) {
return "green";
}
if (level === 1) {
return "orange";
}
if (level === 2) {
return "red";
}
};
export const AtmosControl = (props, context) => {
const { act, data } = useBackend(context);
const [tabIndex, setTabIndex] = useLocalState(context, 'tabIndex', 0);
const decideTab = index => {
switch (index) {
case 0:
return <AtmosControlDataView />;
case 1:
return <AtmosControlMapView />;
default:
return "WE SHOULDN'T BE HERE!";
}
};
return (
<Window resizable>
<Window.Content>
<Box fillPositionedParent>
<Tabs>
<Tabs.Tab
key="DataView"
selected={0 === tabIndex}
onClick={() => setTabIndex(0)}>
<Icon name="table" /> Data View
</Tabs.Tab>
<Tabs.Tab
key="MapView"
selected={1 === tabIndex}
onClick={() => setTabIndex(1)}>
<Icon name="map-marked-alt" /> Map View
</Tabs.Tab>
</Tabs>
{decideTab(tabIndex)}
</Box>
</Window.Content>
</Window>
);
};
const AtmosControlDataView = (_properties, context) => {
const { act, data } = useBackend(context);
const { alarms } = data;
return (
<Box>
<Table m="0.5rem">
<Table.Row header>
<Table.Cell>
Name
</Table.Cell>
<Table.Cell>
Status
</Table.Cell>
<Table.Cell>
Access
</Table.Cell>
</Table.Row>
{alarms.map(a => (
<Table.Row key={a.name}>
<TableCell>
{a.name}
</TableCell>
<TableCell>
{getStatus(a.danger)}
</TableCell>
<TableCell>
<Button
icon="cog"
content="Access"
onClick={() => act('open_alarm', {
aref: a.ref,
})} />
</TableCell>
</Table.Row>
))}
</Table>
</Box>
);
};
const AtmosControlMapView = (_properties, context) => {
const { data } = useBackend(context);
const [zoom, setZoom] = useLocalState(context, 'zoom', 1);
const { alarms } = data;
return (
<Box height="526px" mb="0.5rem" overflow="hidden">
<NanoMap onZoom={v => setZoom(v)}>
{alarms.filter(a => a.z === 1).map(aa => (
// The AA means air alarm, and nothing else
<NanoMap.Marker
key={aa.ref}
x={aa.x}
y={aa.y}
zoom={zoom}
icon="circle"
tooltip={aa.name}
color={getStatusColour(aa.danger)}
/>
))}
</NanoMap>
</Box>
);
};
File diff suppressed because one or more lines are too long