diff --git a/code/game/machinery/computer/atmos_computers/__identifiers.dm b/code/game/machinery/computer/atmos_computers/__identifiers.dm index 381fedd5bd0..ffb4d8aa479 100644 --- a/code/game/machinery/computer/atmos_computers/__identifiers.dm +++ b/code/game/machinery/computer/atmos_computers/__identifiers.dm @@ -30,6 +30,7 @@ #define ATMOS_GAS_MONITOR_ORDNANCE_FREEZER "ordnancefreezer" #define ATMOS_GAS_MONITOR_DISTRO "distro" #define ATMOS_GAS_MONITOR_WASTE "waste" +#define ATMOS_GAS_MONITOR_ENGINE "engine" ///maps a chamber id to its air sensor #define CHAMBER_SENSOR_FROM_ID(chamber_id) ((chamber_id) + "_sensor") @@ -67,4 +68,5 @@ GLOBAL_LIST_INIT(station_gas_chambers, list( ATMOS_GAS_MONITOR_ORDNANCE_FREEZER = "Ordnance Freezer Chamber", ATMOS_GAS_MONITOR_DISTRO = "Distribution Loop", ATMOS_GAS_MONITOR_WASTE = "Waste Loop", + ATMOS_GAS_MONITOR_ENGINE = "Supermatter Engine Chamber", )) diff --git a/code/game/machinery/computer/atmos_computers/_air_sensor.dm b/code/game/machinery/computer/atmos_computers/_air_sensor.dm index aca8b7ef43d..45d705236d3 100644 --- a/code/game/machinery/computer/atmos_computers/_air_sensor.dm +++ b/code/game/machinery/computer/atmos_computers/_air_sensor.dm @@ -60,10 +60,8 @@ input.chamber_id = chamber_id GLOB.objects_by_id_tag[CHAMBER_INPUT_FROM_ID(chamber_id)] = input balloon_alert(user, "connected to input") - else if(istype(multi_tool.buffer, /obj/machinery/atmospherics/components/unary/vent_pump)) var/obj/machinery/atmospherics/components/unary/vent_pump/output = multi_tool.buffer - //so its no longer controlled by air alarm output.disconnect_from_area() //configuration copied from /obj/machinery/atmospherics/components/unary/vent_pump/siphon @@ -71,9 +69,11 @@ output.pressure_checks = ATMOS_INTERNAL_BOUND output.internal_pressure_bound = 4000 output.external_pressure_bound = 0 - output.chamber_id = chamber_id GLOB.objects_by_id_tag[CHAMBER_OUTPUT_FROM_ID(chamber_id)] = output balloon_alert(user, "connected to output") + else + multi_tool.buffer = src + balloon_alert(user, "added to multitool buffer") return TRUE diff --git a/code/game/machinery/computer/atmos_computers/air_sensors.dm b/code/game/machinery/computer/atmos_computers/air_sensors.dm index bd28bcbae3a..723ffacb2eb 100644 --- a/code/game/machinery/computer/atmos_computers/air_sensors.dm +++ b/code/game/machinery/computer/atmos_computers/air_sensors.dm @@ -85,7 +85,7 @@ /obj/machinery/air_sensor/antinoblium_tank name = "antinoblium tank gas sensor" chamber_id = ATMOS_GAS_MONITOR_ANTINOBLIUM - + /obj/machinery/air_sensor/incinerator_tank name = "incinerator chamber gas sensor" chamber_id = ATMOS_GAS_MONITOR_INCINERATOR @@ -97,3 +97,7 @@ /obj/machinery/air_sensor/ordnance_freezer_chamber name = "ordnance freezer chamber gas sensor" chamber_id = ATMOS_GAS_MONITOR_ORDNANCE_FREEZER + +/obj/machinery/air_sensor/engine_chamber + name = "supermatter engine chamber gas sensor" + chamber_id = ATMOS_GAS_MONITOR_ENGINE diff --git a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm index b1f1967a993..5564d7974cd 100644 --- a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm +++ b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm @@ -57,6 +57,13 @@ /// Used for air alarm helper called tlv_no_ckecks to remove alarm thresholds. var/tlv_no_checks = FALSE + /// Used for connecting air alarm to a remote tile/zone via air sensor instead of the tile/zone of the air alarm + var/obj/machinery/air_sensor/connected_sensor + /// Used to link air alarm to air sensor via map helpers + var/air_sensor_chamber_id = "" + /// Whether it is possible to link/unlink this air alarm from a sensor + var/allow_link_change = TRUE + GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) @@ -92,7 +99,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) else tlv_collection[gas_path] = new /datum/tlv/no_checks - my_area = get_area(src) + my_area = connected_sensor ? get_area(connected_sensor) : get_area(src) alarm_manager = new(src) select_mode(src, /datum/air_alarm_mode/filtering) @@ -121,7 +128,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) return . = ..() - my_area = area_to_register + my_area = connected_sensor ? get_area(connected_sensor) : area_to_register update_appearance() /obj/machinery/airalarm/update_name(updates) @@ -134,7 +141,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) return . = ..() - my_area = null + my_area = connected_sensor ? get_area(connected_sensor) : null /obj/machinery/airalarm/examine(mob/user) . = ..() @@ -153,6 +160,19 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) return ..() return UI_CLOSE +/obj/machinery/airalarm/multitool_act(mob/living/user, obj/item/multitool/multi_tool) + .= ..() + + if (!istype(multi_tool) || locked) + return . + + if(istype(multi_tool.buffer, /obj/machinery/air_sensor)) + if(!allow_link_change) + balloon_alert(user, "linking disabled") + return TOOL_ACT_SIGNAL_BLOCKING + connect_sensor(multi_tool.buffer) + balloon_alert(user, "connected sensor") + return TOOL_ACT_TOOLTYPE_SUCCESS /obj/machinery/airalarm/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -180,14 +200,21 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) data["dangerLevel"] = danger_level data["atmosAlarm"] = !!my_area.active_alarms[ALARM_ATMOS] data["fireAlarm"] = my_area.fire + data["sensor"] = !!connected_sensor + data["allowLinkChange"] = allow_link_change - var/turf/turf = get_turf(src) + var/turf/turf = connected_sensor ? get_turf(connected_sensor) : get_turf(src) var/datum/gas_mixture/environment = turf.return_air() var/total_moles = environment.total_moles() var/temp = environment.temperature var/pressure = environment.return_pressure() data["envData"] = list() + if(connected_sensor) + data["envData"] += list(list( + "name" = "Linked area", + "value" = my_area.name + )) data["envData"] += list(list( "name" = "Pressure", "value" = "[round(pressure, 0.01)] kPa", @@ -287,7 +314,8 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) return var/mob/user = usr - var/area/area = get_area(src) + var/area/area = connected_sensor ? get_area(connected_sensor) : get_area(src) + ASSERT(!isnull(area)) var/ref = params["ref"] @@ -394,7 +422,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) tlv.set_value(threshold_type, value) investigate_log("threshold value for [threshold]:[threshold_type] was set to [value] by [key_name(usr)]", INVESTIGATE_ATMOS) - var/turf/our_turf = get_turf(src) + var/turf/our_turf = connected_sensor ? get_turf(connected_sensor) : get_turf(src) var/datum/gas_mixture/environment = our_turf.return_air() check_danger(our_turf, environment, environment.temperature) @@ -407,7 +435,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) tlv.reset_value(threshold_type) investigate_log("threshold value for [threshold]:[threshold_type] was reset by [key_name(usr)]", INVESTIGATE_ATMOS) - var/turf/our_turf = get_turf(src) + var/turf/our_turf = connected_sensor ? get_turf(connected_sensor) : get_turf(src) var/datum/gas_mixture/environment = our_turf.return_air() check_danger(our_turf, environment, environment.temperature) @@ -419,6 +447,10 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) if (alarm_manager.clear_alarm(ALARM_ATMOS)) danger_level = AIR_ALARM_ALERT_NONE + if ("disconnect_sensor") + if(allow_link_change) + disconnect_sensor() + update_appearance() return TRUE @@ -557,3 +589,29 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/airalarm, 24) /obj/machinery/airalarm/proc/set_tlv_no_checks() tlv_collection["temperature"] = new /datum/tlv/no_checks tlv_collection["pressure"] = new /datum/tlv/no_checks + +///Used for air alarm link helper, which connects air alarm to a sensor with corresponding chamber_id +/obj/machinery/airalarm/proc/setup_chamber_link() + var/obj/machinery/air_sensor/sensor = GLOB.objects_by_id_tag[CHAMBER_SENSOR_FROM_ID(air_sensor_chamber_id)] + if(isnull(sensor)) + log_mapping("[src] at [AREACOORD(src)] tried to connect to a sensor, but no sensor with chamber_id:[air_sensor_chamber_id] found!") + return + connect_sensor(sensor) + +///Used to connect air alarm with a sensor +/obj/machinery/airalarm/proc/connect_sensor(obj/machinery/air_sensor/sensor) + if(!isnull(connected_sensor)) + UnregisterSignal(connected_sensor, COMSIG_PARENT_QDELETING) + connected_sensor = sensor + RegisterSignal(connected_sensor, COMSIG_PARENT_QDELETING, PROC_REF(disconnect_sensor)) + my_area = get_area(connected_sensor) + update_name() + check_danger() + +///Used to reset the air alarm to default configuration after disconnecting from air sensor +/obj/machinery/airalarm/proc/disconnect_sensor() + UnregisterSignal(connected_sensor, COMSIG_PARENT_QDELETING) + connected_sensor = null + my_area = get_area(src) + update_name() + check_danger() diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index 4100fe5e687..1d4c74d93ed 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -253,7 +253,7 @@ //air alarm helpers /obj/effect/mapping_helpers/airalarm desc = "You shouldn't see this. Report it please." - layer = DOOR_HELPER_LAYER + layer = ABOVE_OBJ_LAYER late = TRUE /obj/effect/mapping_helpers/airalarm/Initialize(mapload) @@ -301,6 +301,9 @@ if(target.syndicate_access + target.away_general_access + target.engine_access + target.mixingchamber_access + target.all_access > 1) CRASH("Tried to combine incompatible air alarm access helpers!") + if(target.air_sensor_chamber_id) + target.setup_chamber_link() + target.update_appearance() qdel(src) @@ -387,6 +390,26 @@ log_mapping("[src] at [AREACOORD(src)] [(area.type)] tried to adjust [target]'s tlv to no_checks but it's already changed!") target.tlv_no_checks = TRUE +/obj/effect/mapping_helpers/airalarm/link + name = "airalarm link helper" + icon_state = "airalarm_link_helper" + var/chamber_id = "" + var/allow_link_change = FALSE + +/obj/effect/mapping_helpers/airalarm/link/Initialize(mapload) + . = ..() + if(!mapload) + log_mapping("[src] spawned outside of mapload!") + return INITIALIZE_HINT_QDEL + + var/obj/machinery/airalarm/alarm = locate(/obj/machinery/airalarm) in loc + if(!isnull(alarm)) + alarm.air_sensor_chamber_id = chamber_id + alarm.allow_link_change = allow_link_change + else + log_mapping("[src] failed to find air alarm at [AREACOORD(src)].") + return INITIALIZE_HINT_QDEL + //apc helpers /obj/effect/mapping_helpers/apc desc = "You shouldn't see this. Report it please." diff --git a/icons/effects/mapping_helpers.dmi b/icons/effects/mapping_helpers.dmi index d75ed305651..335ba9a57a8 100644 Binary files a/icons/effects/mapping_helpers.dmi and b/icons/effects/mapping_helpers.dmi differ diff --git a/tgui/packages/tgui/interfaces/AirAlarm.tsx b/tgui/packages/tgui/interfaces/AirAlarm.tsx index 7dd02230cd3..78e3c02847e 100644 --- a/tgui/packages/tgui/interfaces/AirAlarm.tsx +++ b/tgui/packages/tgui/interfaces/AirAlarm.tsx @@ -13,6 +13,8 @@ type AirAlarmData = { dangerLevel: 0 | 1 | 2; atmosAlarm: BooleanLike; // fix this fireAlarm: BooleanLike; + sensor: BooleanLike; + allowLinkChange: BooleanLike; envData: { name: string; value: string; // preformatted in backend, shorter code that way. @@ -167,7 +169,14 @@ const AirAlarmControl = (props, context) => { const AirAlarmControlHome = (props, context) => { const { act, data } = useBackend(context); const [screen, setScreen] = useLocalState(context, 'screen', 'home'); - const { selectedModePath, panicSiphonPath, filteringPath, atmosAlarm } = data; + const { + selectedModePath, + panicSiphonPath, + filteringPath, + atmosAlarm, + sensor, + allowLinkChange, + } = data; const isPanicSiphoning = selectedModePath === panicSiphonPath; return ( <> @@ -212,6 +221,16 @@ const AirAlarmControlHome = (props, context) => { content="Alarm Thresholds" onClick={() => setScreen('thresholds')} /> + {!!sensor && !!allowLinkChange && ( + + act('disconnect_sensor')} + /> + + )} ); }; @@ -364,16 +383,16 @@ const AirAlarmControlThresholds = (props, context) => { Threshold - Minimum Hazard + Danger Below - Minimum Warning + Warning Below - Maximum Warning + Warning Above - Maximum Hazard + Danger Above Actions