#define ACA_SCREEN_DETAILSVIEW 1 #define ACA_SCREEN_ADMINPANEL 2 var/global/list/atmos_controllers = list() /obj/item/weapon/circuitboard/atmoscontrol name = "\improper Central Atmospherics Computer Circuitboard" build_path = /obj/machinery/computer/atmoscontrol /obj/machinery/computer/atmoscontrol name = "\improper Central Atmospherics Computer" icon = 'icons/obj/computer.dmi' icon_state = "tank" density = 1 anchored = 1.0 circuit = "/obj/item/weapon/circuitboard/atmoscontrol" var/obj/machinery/alarm/current var/list/filter=null var/obj/item/weapon/card/id/log_in_id = null //the ID that's currently logged in var/screen = ACA_SCREEN_DETAILSVIEW //the current screen in the UI var/datum/airalarm_preset/selected_preset = null //stores the preset settings while they're being edited machine_flags = EMAGGABLE light_color = LIGHT_COLOR_CYAN /obj/machinery/computer/atmoscontrol/New() ..() atmos_controllers += src /obj/machinery/computer/atmoscontrol/Destroy() atmos_controllers -= src ..() /obj/machinery/computer/atmoscontrol/xeno name = "\improper Xenobiology Atmospherics Computer" filter=list( /area/science/xenobiology/specimen_1, /area/science/xenobiology/specimen_2, /area/science/xenobiology/specimen_3, /area/science/xenobiology/specimen_4, /area/science/xenobiology/specimen_5, /area/science/xenobiology/specimen_6 ) /obj/machinery/computer/atmoscontrol/gas_chamber name = "\improper Gas Chamber Atmospherics Computer" filter=list( /area/security/gas_chamber ) /obj/machinery/computer/atmoscontrol/attack_ai(var/mob/user as mob) src.add_hiddenprint(user) return interact(user) /obj/machinery/computer/atmoscontrol/attack_paw(var/mob/user as mob) return interact(user) /obj/machinery/computer/atmoscontrol/attack_hand(mob/user) if(..()) return return interact(user) /obj/machinery/computer/atmoscontrol/attackby(var/obj/item/I as obj, var/mob/user as mob) if(istype(I, /obj/item/weapon/card/emag)) return //lazy hackfix for the UI opening and not updating when using an emag with the UI closed return ..() /obj/machinery/computer/atmoscontrol/interact(mob/user) return ui_interact(user) /obj/machinery/computer/atmoscontrol/emag_act(var/mob/user as mob, var/obj/item/weapon/card/E as obj) if(!emagged) emagged = 1 spark(src, 1, FALSE) user.visible_message("\The [user] swipes \a [E] through \the [src], causing the screen to flash!",\ "You swipe \the [E] through \the [src], the screen flashing as you gain full control.",\ "You hear the swipe of a card through a reader, and an electronic warble.") nanomanager.update_uis(src) return 1 //largely copypasted from air alarms /obj/machinery/computer/atmoscontrol/proc/set_threshold(var/list/thresholds, var/threshold_name, var/index, var/value) if (value<0) thresholds[index] = -1.0 else if (threshold_name=="temperature" && value>5000) thresholds[index] = 5000 else if (threshold_name=="pressure" && value>50*ONE_ATMOSPHERE) thresholds[index] = 50*ONE_ATMOSPHERE else if (threshold_name!="temperature" && threshold_name!="pressure" && value>200) thresholds[index] = 200 else value = round(value,0.01) thresholds[index] = value //blegh if(index == 1) if(thresholds[1] > thresholds[2]) thresholds[2] = thresholds[1] if(thresholds[1] > thresholds[3]) thresholds[3] = thresholds[1] if(thresholds[1] > thresholds[4]) thresholds[4] = thresholds[1] if(index == 2) if(thresholds[1] > thresholds[2]) thresholds[1] = thresholds[2] if(thresholds[2] > thresholds[3]) thresholds[3] = thresholds[2] if(thresholds[2] > thresholds[4]) thresholds[4] = thresholds[2] if(index == 3) if(thresholds[1] > thresholds[3]) thresholds[1] = thresholds[3] if(thresholds[2] > thresholds[3]) thresholds[2] = thresholds[3] if(thresholds[3] > thresholds[4]) thresholds[4] = thresholds[3] if(index == 4) if(thresholds[1] > thresholds[4]) thresholds[1] = thresholds[4] if(thresholds[2] > thresholds[4]) thresholds[2] = thresholds[4] if(thresholds[3] > thresholds[4]) thresholds[3] = thresholds[4] /obj/machinery/computer/atmoscontrol/proc/apply_preset(var/presetname) var/list/done_areas = list() //a little optimization to avoid needlessly repeating apply_mode() for(var/obj/machinery/alarm/alarm in machines) if(alarm.preset != presetname) continue if(alarm.rcon_setting == RCON_NO) continue //no messing with alarms with no remote control if(log_in_id) if(!emagged && !usr.hasFullAccess() && !alarm.check_access(log_in_id)) continue //The logged in ID has no access to this card, and the user isn't an all-access user (eg. admin ghost, AI, etc.) else if(!emagged && !usr.hasFullAccess()) continue var/area/alarm_area = get_area(alarm) if(alarm_area in done_areas) continue alarm.apply_preset(1, 1) //no cycle, propagate done_areas += alarm_area //switches all air alarms from old preset to new preset /obj/machinery/computer/atmoscontrol/proc/switch_preset(var/oldpreset, var/newpreset, var/no_cycle_after=1) if(!(newpreset in airalarm_presets)) return var/list/done_areas = list() //a little optimization to avoid needlessly repeating apply_mode() for(var/obj/machinery/alarm/alarm in machines) if(alarm.preset != oldpreset) continue if(alarm.rcon_setting == RCON_NO) continue //no messing with alarms with no remote control if(log_in_id) if(!emagged && !usr.hasFullAccess() && !alarm.check_access(log_in_id)) continue //The logged in ID has no access to this card, and the user isn't an all-access user (eg. admin ghost, AI, etc.) else if(!emagged && !usr.hasFullAccess()) continue var/area/alarm_area = get_area(alarm) if(alarm_area in done_areas) continue alarm.preset = newpreset alarm.apply_preset(no_cycle_after, 1) //optionally cycle, propagate done_areas += alarm_area /obj/machinery/computer/atmoscontrol/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open=NANOUI_FOCUS) if(user.client) var/datum/asset/simple/nanoui_maps/asset_datum = new send_asset_list(user.client, asset_datum.assets) var/list/data[0] data["alarm"]=null if(log_in_id) data["logged_in"] = TRUE data["login_name"] = log_in_id.registered_name + (log_in_id.assignment ? ", [log_in_id.assignment]" : null) else if(user.hasFullAccess()) data["logged_in"] = TRUE else data["logged_in"] = FALSE if(emagged) data["logged_in"] = TRUE data["login_name"] = "Robert');DROP TABLE users;" //honk data["emagged"] = emagged if(current) data += current.get_nano_data(user,TRUE) data["alarm"] = "\ref[current]" data["name"] = current.name else var/list/alarms=list() for(var/obj/machinery/alarm/alarm in sortNames(machines)) // removing sortAtom because nano updates it just enough for the lag to happen if(log_in_id) if(!emagged && !user.hasFullAccess() && !alarm.check_access(log_in_id)) continue //The logged in ID has no access to this card, and the user isn't an all-access user (eg. admin ghost, AI, etc.) else if(!emagged && !user.hasFullAccess()) continue var/area/alarm_area = get_area(alarm) var/turf/pos = get_turf(alarm) var/list/alarm_data=list() alarm_data["ID"]="\ref[alarm]" alarm_data["danger"] = max(alarm.local_danger_level, alarm_area.atmosalm-1) alarm_data["name"] = "[alarm]" alarm_data["area"] = get_area(alarm) alarm_data["x"] = pos.x alarm_data["y"] = pos.y alarm_data["z"] = pos.z alarms+=list(alarm_data) data["alarms"]=alarms var/list/tmplist = list() for(var/preset in airalarm_presets) //this is a global list defined in alarm.dm var/datum/airalarm_preset/preset_datum = airalarm_presets[preset] tmplist[++tmplist.len] = list( "name" = preset_datum.name, "desc" = preset_datum.desc, "core" = preset_datum.core, "oxygen" = preset_datum.oxygen, "nitrogen" = preset_datum.nitrogen, "carbon_dioxide" = preset_datum.carbon_dioxide, "plasma" = preset_datum.plasma, "n2o" = preset_datum.n2o, "other" = preset_datum.other, "pressure" = preset_datum.pressure, "temperature" = preset_datum.temperature, "target_temperature" = preset_datum.target_temperature, "scrubbers_gases" = preset_datum.scrubbers_gases ) data["presets"] = tmplist if(selected_preset) data["selected_preset"] = list( "name" = selected_preset.name, "desc" = selected_preset.desc, "core" = selected_preset.core, "oxygen" = selected_preset.oxygen, "nitrogen" = selected_preset.nitrogen, "carbon_dioxide" = selected_preset.carbon_dioxide, "plasma" = selected_preset.plasma, "n2o" = selected_preset.n2o, "other" = selected_preset.other, "pressure" = selected_preset.pressure, "temperature" = selected_preset.temperature, "target_temperature" = selected_preset.target_temperature, "scrubbers_gases" = selected_preset.scrubbers_gases ) data["selected_preset_name"] = selected_preset.name else data["selected_preset"] = null data["selected_preset_name"] = null if(log_in_id && (access_ce in log_in_id.GetAccess()) || emagged || user.hasFullAccess()) data["admin_access"] = TRUE else data["admin_access"] = FALSE screen = ACA_SCREEN_DETAILSVIEW //this dumb hack stops unauthorized cards from seeing shit they shouldn't data["aca_screen"] = screen //aca_screen so we don't conflict with air alarms, which already use screen ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if(!ui) ui = new(user, src, ui_key, "atmos_control.tmpl", name, 900, 800) // adding a template with the key "mapContent" enables the map ui functionality ui.add_template("mapContent", "atmos_control_map_content.tmpl") // adding a template with the key "mapHeader" replaces the map header content ui.add_template("mapHeader", "atmos_control_map_header.tmpl") ui.set_show_map(FALSE) ui.set_initial_data(data) ui.open() ui.set_auto_update(!!current) //a bunch of this is copied from atmos alarms /obj/machinery/computer/atmoscontrol/Topic(href, href_list) if(..()) return 1 if(href_list["set_screen"]) screen = href_list["set_screen"] return 1 if(href_list["login"]) if(log_in_id || emagged) return 1 var/mob/M = usr var/obj/item/weapon/card/id/I = M.get_active_hand() if (istype(I, /obj/item/device/pda)) var/obj/item/device/pda/pda = I I = pda.id if (istype(I,/obj/item/weapon/card/emag)) emag_act(I, usr) if (I && istype(I)) log_in_id = I return 1 if(href_list["logout"]) if(!emagged) log_in_id = null return 1 if(href_list["close"]) if(usr.machine == src) usr.unset_machine() return 1 if(href_list["reset"]) current = null return 1 if(href_list["alarm"]) current = locate(href_list["alarm"]) return 1 if(href_list["select_preset"]) if(!(log_in_id && (access_ce in log_in_id.GetAccess()) || emagged || usr.hasFullAccess())) return 1 selected_preset = new(airalarm_presets[href_list["select_preset"]]) //copy the existing preset for editing return 1 if(href_list["add_preset"]) if(!(log_in_id && (access_ce in log_in_id.GetAccess()) || emagged || usr.hasFullAccess())) return 1 var/name = trimcenter(trim(stripped_input(usr,"Enter the name for the preset (max 12 characters).", "Preset name",""),1,12)) if(!name || name == "") to_chat(usr, "Invalid name.") return 1 if(name in airalarm_presets) to_chat(usr, "Preset with that name already exists.") return 1 var/desc = trimcenter(trim(stripped_input(usr,"Enter the description for the preset (max 50 characters).", "Preset name",""),1,50)) if(!desc || desc == "") to_chat(usr, "Invalid description.") return 1 //use the settings from whatever was previously selected to add this new one, but make sure it's not core (ie. can be deleted) selected_preset = new(selected_preset, name, desc, FALSE) airalarm_presets[name] = new /datum/airalarm_preset(selected_preset) //we'll put a copy of 'er in instead of the real deal return 1 if(href_list["save_preset_setting"]) if(!(log_in_id && (access_ce in log_in_id.GetAccess()) || emagged || usr.hasFullAccess())) return 1 var/name = selected_preset.name airalarm_presets[name] = new /datum/airalarm_preset(selected_preset) //make a copy //re-apply preset on all air alarms that have it enabled apply_preset(name) to_chat(usr, "Preset saved and reapplied to alarms.") return 1 if(href_list["rename_preset"]) if(!(log_in_id && (access_ce in log_in_id.GetAccess()) || emagged || usr.hasFullAccess())) return 1 //renames the currently selected preset if(selected_preset.core) to_chat(usr, "This preset cannot be renamed.") return 1 var/newname = trimcenter(trim(stripped_input(usr,"Enter the name for the preset (max 12 characters).", "Preset name",""),1,12)) if(!newname || newname == "") to_chat(usr, "Invalid name.") return 1 var/newdesc = trimcenter(trim(stripped_input(usr,"Enter the description for the preset (max 50 characters).", "Preset name",""),1,50)) if(!newdesc || newdesc == "") to_chat(usr, "Invalid description.") return 1 //add the fresh preset to the list first airalarm_presets[newname] = new /datum/airalarm_preset(selected_preset, newname, newdesc) //transfer all the alarms from old preset to new preset var/oldname = selected_preset.name switch_preset(oldname, newname) //delete the old preset and set the new one as selected selected_preset = new /datum/airalarm_preset(selected_preset, newname, newdesc) airalarm_presets.Remove(oldname) return 1 if(href_list["delete_preset"]) if(!(log_in_id && (access_ce in log_in_id.GetAccess()) || emagged || usr.hasFullAccess())) return 1 //deletes the currently selected preset if possible if(selected_preset.core) to_chat(usr, "This preset cannot be deleted.") return 1 //put every alarm that used to be on this preset to the Human preset var/oldname = selected_preset.name switch_preset(oldname, "Human") selected_preset = new /datum/airalarm_preset(airalarm_presets["Human"]) //set the current Human preset as active airalarm_presets.Remove(oldname) return 1 if(href_list["reset_preset"]) if(!(log_in_id && (access_ce in log_in_id.GetAccess()) || emagged || usr.hasFullAccess())) return 1 //resets the currently selected core preset if(!selected_preset.core) to_chat(usr, "This preset cannot be reset.") return 1 //this is some shitcode var/name = selected_preset.name switch(name) if("Human") selected_preset = new /datum/airalarm_preset/human if("Vox") selected_preset = new /datum/airalarm_preset/vox if("Coldroom") selected_preset = new /datum/airalarm_preset/coldroom if("Plasmaman") selected_preset = new /datum/airalarm_preset/plasmaman return 1 if(href_list["apply_preset_batch"]) if(!(log_in_id && (access_ce in log_in_id.GetAccess()) || emagged || usr.hasFullAccess())) return 1 //save preset var/newname = selected_preset.name airalarm_presets[newname] = new /datum/airalarm_preset(selected_preset) //make a copy var/oldname = input("Select the preset you want to switch over from.\n\nAll air alarms currently on this preset will be switched over to the [newname] preset.", "Select preset", newname) in airalarm_presets if(!oldname) to_chat(usr, "Invalid selection!") var/no_cycle_after = alert(usr, "Cycle (remove air then refill) after switching?",,"Yes", "No") == "Yes" ? 0 : 1 switch_preset(oldname, newname, no_cycle_after) to_chat(usr, "Preset batch applied.") return 1 if(href_list["set_preset_setting"]) if(!(log_in_id && (access_ce in log_in_id.GetAccess()) || emagged || usr.hasFullAccess())) return 1 switch(href_list["set_preset_setting"]) if("oxygen", "nitrogen", "carbon_dioxide", "plasma", "n2o", "other", "pressure", "temperature") //this could be better... var/selected = null switch(href_list["set_preset_setting"]) if("oxygen") selected = selected_preset.oxygen if("nitrogen") selected = selected_preset.nitrogen if("carbon_dioxide") selected = selected_preset.carbon_dioxide if("plasma") selected = selected_preset.plasma if("n2o") selected = selected_preset.n2o if("other") selected = selected_preset.other if("pressure") selected = selected_preset.pressure if("temperature") selected = selected_preset.temperature if(selected == null) return 1 //this should never happen var/env = href_list["set_preset_setting"] var/index = text2num(href_list["index"]) var/list/thresholds = list("lower bound", "low warning", "high warning", "upper bound") var/newval = input("Enter [thresholds[index]] for [env]", "Alarm triggers", selected[index]) as num|null if (isnull(newval)) return 1 set_threshold(selected, href_list["set_preset_setting"], index, newval) return 1 if("target_temperature") var/max_temperature = MAX_TARGET_TEMPERATURE - T0C //these defines should come from code\game\machinery\alarm.dm var/min_temperature = MIN_TARGET_TEMPERATURE - T0C var/input_temperature = input("What temperature (in C) would you like the system to target? (Capped between [min_temperature]C and [max_temperature]C).\n\nNote that the cooling unit in this air alarm can not go below [MIN_TEMPERATURE]C or above [MAX_TEMPERATURE]C by itself. ", "Thermostat Controls") as num|null if(input_temperature==null) return 1 if(!input_temperature || input_temperature >= max_temperature || input_temperature <= min_temperature) to_chat(usr, "Temperature must be between [min_temperature]C and [max_temperature]C.") else input_temperature = input_temperature + T0C selected_preset.target_temperature = input_temperature return 1 if("scrubbers_gases") var/gas = href_list["gas"] if(gas && (gas in selected_preset.scrubbers_gases)) selected_preset.scrubbers_gases[gas] = !selected_preset.scrubbers_gases[gas] //toggle scrubbing for it return 1 if(current) if(log_in_id) if(!emagged && !usr.hasFullAccess() && !current.check_access(log_in_id) && !issilicon(usr)) return 1 //The logged in ID has no access to this card, and the user isn't an all-access user (eg. admin ghost, AI, etc.) else if(!emagged && !usr.hasFullAccess() && !issilicon(usr)) return 1 if(href_list["command"]) if(current.rcon_setting == RCON_NO) return 1 var/device_id = href_list["id_tag"] switch(href_list["command"]) if( "power", "adjust_external_pressure", "set_external_pressure", "set_internal_pressure", "checks", "co2_scrub", "tox_scrub", "n2o_scrub", "o2_scrub", "n2_scrub", "panic_siphon", "scrubbing") var/val if(href_list["val"]) val=text2num(href_list["val"]) else var/newval = input("Enter new value") as num|null if(isnull(newval)) return 1 if(href_list["command"]=="set_external_pressure") if(newval>1000+ONE_ATMOSPHERE) newval = 1000+ONE_ATMOSPHERE if(newval<0) newval = 0 val = newval current.send_signal(device_id, list(href_list["command"] = val ) ) if("set_threshold") var/env = href_list["env"] var/threshold = text2num(href_list["var"]) var/list/selected = current.TLV[env] var/list/thresholds = list("lower bound", "low warning", "high warning", "upper bound") var/newval = input("Enter [thresholds[threshold]] for [env]", "Alarm triggers", selected[threshold]) as num|null if (isnull(newval)) return 1 current.set_threshold(env, threshold, newval, 1) return 1 if(href_list["reset_thresholds"]) if(current.rcon_setting == RCON_NO) return 1 current.apply_preset(1) //just apply the preset without cycling return 1 if(href_list["screen"]) current.screen = text2num(href_list["screen"]) return 1 if(href_list["atmos_alarm"]) if(current.rcon_setting == RCON_NO) return 1 current.set_alarm(1) return 1 if(href_list["atmos_reset"]) if(current.rcon_setting == RCON_NO) return 1 current.set_alarm(0) return 1 if(href_list["mode"]) if(current.rcon_setting == RCON_NO) return 1 current.mode = text2num(href_list["mode"]) current.apply_mode() return 1 if(href_list["toggle_cycle_after_preset"]) if(current.rcon_setting == RCON_NO) return 1 current.cycle_after_preset = !current.cycle_after_preset return 1 if(href_list["preset"]) if(current.rcon_setting == RCON_NO) return 1 if(href_list["preset"] in airalarm_presets) current.preset = href_list["preset"] current.apply_preset(!current.cycle_after_preset) return 1 if(href_list["temperature"]) if(current.rcon_setting == RCON_NO) return 1 var/list/selected = current.TLV["temperature"] var/max_temperature var/min_temperature if(!current.locked) max_temperature = MAX_TARGET_TEMPERATURE - T0C //these defines should come from code\game\machinery\alarm.dm min_temperature = MIN_TARGET_TEMPERATURE - T0C else max_temperature = selected[3] - T0C min_temperature = selected[2] - T0C var/input_temperature = input("What temperature (in C) would you like the system to target? (Capped between [min_temperature]C and [max_temperature]C).\n\nNote that the cooling unit in this air alarm can not go below [MIN_TEMPERATURE]C or above [MAX_TEMPERATURE]C by itself. ", "Thermostat Controls") as num|null if(input_temperature==null) return 1 if(!input_temperature || input_temperature >= max_temperature || input_temperature <= min_temperature) to_chat(usr, "Temperature must be between [min_temperature]C and [max_temperature]C.") else input_temperature = input_temperature + T0C current.set_temperature(input_temperature) return 1 #undef ACA_SCREEN_DETAILSVIEW #undef ACA_SCREEN_ADMINPANEL