diff --git a/code/__DEFINES/dcs/signals/signals_area.dm b/code/__DEFINES/dcs/signals/signals_area.dm index f1f6747d4b1..df5104cd885 100644 --- a/code/__DEFINES/dcs/signals/signals_area.dm +++ b/code/__DEFINES/dcs/signals/signals_area.dm @@ -14,10 +14,18 @@ #define COMSIG_EXIT_AREA "exit_area" // Alarm listener datum signals -///Sent when an alarm is fired (alarm, area/source_area) -#define COMSIG_ALARM_TRIGGERED "comsig_alarm_triggered" -///Send when an alarm source is cleared (alarm_type, area/source_area) -#define COMSIG_ALARM_CLEARED "comsig_alarm_clear" +///Sent when an alarm is fired and an alarm listener has tracked onto it (alarm, area/source_area) +#define COMSIG_ALARM_LISTENER_TRIGGERED "alarm_listener_triggered" +///Send when an alarm source is cleared and an alarm listener has tracked onto it (alarm_type, area/source_area) +#define COMSIG_ALARM_LISTENER_CLEARED "alarm_listener_clear" + +/// Called when an alarm handler fires an alarm +#define COMSIG_ALARM_TRIGGERED "alarm_triggered" +/// Called when an alarm handler clears an alarm +#define COMSIG_ALARM_CLEARED "alarm_cleared" + +/// Called when the air alarm mode is updated +#define COMSIG_AIRALARM_UPDATE_MODE "airalarm_update_mode" // Area fire signals /// Sent when an area's fire var changes: (fire_value) diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index 17ff3893d21..2cd4735c8f5 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -59,9 +59,9 @@ #define COMSIG_WEATHER_WINDDOWN(event_type) "!weather_winddown [event_type]" #define COMSIG_WEATHER_END(event_type) "!weather_end [event_type]" /// An alarm of some form was sent (datum/alarm_handler/source, alarm_type, area/source_area) -#define COMSIG_ALARM_FIRE(alarm_type) "!alarm_fire [alarm_type]" +#define COMSIG_GLOB_ALARM_FIRE(alarm_type) "!alarm_fire [alarm_type]" /// An alarm of some form was cleared (datum/alarm_handler/source, alarm_type, area/source_area) -#define COMSIG_ALARM_CLEAR(alarm_type) "!alarm_clear [alarm_type]" +#define COMSIG_GLOB_ALARM_CLEAR(alarm_type) "!alarm_clear [alarm_type]" ///global mob logged in signal! (/mob/added_player) #define COMSIG_GLOB_MOB_LOGGED_IN "!mob_logged_in" diff --git a/code/datums/alarm.dm b/code/datums/alarm.dm index 63dc6abfae4..c19ff6c0c0b 100644 --- a/code/datums/alarm.dm +++ b/code/datums/alarm.dm @@ -61,7 +61,8 @@ our_area.active_alarms[alarm_type] += 1 - SEND_GLOBAL_SIGNAL(COMSIG_ALARM_FIRE(alarm_type), src, alarm_type, our_area, our_z_level, optional_camera) + SEND_SIGNAL(src, COMSIG_ALARM_TRIGGERED, alarm_type, our_area) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_ALARM_FIRE(alarm_type), src, alarm_type, our_area, our_z_level, optional_camera) return TRUE @@ -95,7 +96,8 @@ if(!length(our_area.active_alarms)) our_area.active_alarms -= alarm_type - SEND_GLOBAL_SIGNAL(COMSIG_ALARM_CLEAR(alarm_type), src, alarm_type, our_area) + SEND_SIGNAL(src, COMSIG_ALARM_CLEARED, alarm_type, our_area) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_ALARM_CLEAR(alarm_type), src, alarm_type, our_area) return TRUE /datum/alarm_listener @@ -114,8 +116,8 @@ src.allowed_z_levels = allowed_z_levels src.allowed_areas = allowed_areas for(var/alarm_type in alarms_to_listen_for) - RegisterSignal(SSdcs, COMSIG_ALARM_FIRE(alarm_type), .proc/add_alarm) - RegisterSignal(SSdcs, COMSIG_ALARM_CLEAR(alarm_type), .proc/clear_alarm) + RegisterSignal(SSdcs, COMSIG_GLOB_ALARM_FIRE(alarm_type), .proc/add_alarm) + RegisterSignal(SSdcs, COMSIG_GLOB_ALARM_CLEAR(alarm_type), .proc/clear_alarm) return ..() @@ -153,7 +155,7 @@ //This does mean that only the first alarm of that camera type in the area will send a ping, but jesus what else can ya do alarms_of_our_type[source_area.name] = list(source_area, cameras, list(handler)) - SEND_SIGNAL(src, COMSIG_ALARM_TRIGGERED, alarm_type, source_area) + SEND_SIGNAL(src, COMSIG_ALARM_LISTENER_TRIGGERED, alarm_type, source_area) ///Removes an alarm to our alarms list, you probably shouldn't be calling this manually ///It should all be handled by the signal listening we do, unless you want to only remove an alarm to one listener @@ -183,7 +185,7 @@ if(!length(alarms_of_our_type)) alarms -= alarm_type - SEND_SIGNAL(src, COMSIG_ALARM_CLEARED, alarm_type, source_area) + SEND_SIGNAL(src, COMSIG_ALARM_LISTENER_CLEARED, alarm_type, source_area) ///Does what it says on the tin, exists for signal hooking /datum/alarm_listener/proc/prevent_alarm_changes() diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm index 8fa4199079f..4af3dfe8cb1 100644 --- a/code/game/machinery/computer/station_alert.dm +++ b/code/game/machinery/computer/station_alert.dm @@ -10,7 +10,7 @@ /obj/machinery/computer/station_alert/Initialize(mapload) alert_control = new(src, list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER), list(z), title = name) - RegisterSignal(alert_control.listener, list(COMSIG_ALARM_TRIGGERED, COMSIG_ALARM_CLEARED), .proc/update_alarm_display) + RegisterSignal(alert_control.listener, list(COMSIG_ALARM_LISTENER_TRIGGERED, COMSIG_ALARM_LISTENER_CLEARED), .proc/update_alarm_display) return ..() /obj/machinery/computer/station_alert/Destroy() diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm index 355aa4a3d6a..53c6849fe8b 100644 --- a/code/game/machinery/doors/airlock_electronics.dm +++ b/code/game/machinery/doors/airlock_electronics.dm @@ -15,6 +15,8 @@ var/passed_cycle_id /// A holder of the electronics, in case of them working as an integrated part var/holder + /// Whether this airlock can have an integrated circuit inside of it or not + var/shell = FALSE /obj/item/electronics/airlock/examine(mob/user) . = ..() @@ -47,6 +49,7 @@ data["unres_direction"] = unres_sides data["passedName"] = passed_name data["passedCycleId"] = passed_cycle_id + data["shell"] = shell return data /obj/item/electronics/airlock/ui_act(action, params) @@ -72,6 +75,9 @@ else accesses -= access . = TRUE + if("set_shell") + shell = !!params["on"] + . = TRUE if("direc_set") var/unres_direction = text2num(params["unres_direction"]) unres_sides ^= unres_direction //XOR, toggles only the bit that was clicked diff --git a/code/game/machinery/porta_turret/portable_turret_construct.dm b/code/game/machinery/porta_turret/portable_turret_construct.dm index 78c2ef1dfaa..d272cc3c86b 100644 --- a/code/game/machinery/porta_turret/portable_turret_construct.dm +++ b/code/game/machinery/porta_turret/portable_turret_construct.dm @@ -109,7 +109,6 @@ to_chat(user, span_notice("You add [I] to the turret.")) build_step = PTURRET_GUN_EQUIPPED return - else if(I.tool_behaviour == TOOL_WRENCH) I.play_tool_sound(src, 100) to_chat(user, span_notice("You remove the turret's metal armor bolts.")) diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index 5720d2a7ede..4fda7841ec8 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -268,6 +268,13 @@ door.electronics = electronics door.heat_proof = heat_proof_finished door.security_level = 0 + if(electronics.shell) + door.AddComponent( \ + /datum/component/shell, \ + unremovable_circuit_components = list(new /obj/item/circuit_component/airlock, new /obj/item/circuit_component/airlock_access_event), \ + capacity = SHELL_CAPACITY_LARGE, \ + shell_flags = SHELL_FLAG_ALLOW_FAILURE_ACTION|SHELL_FLAG_REQUIRE_ANCHOR \ + ) if(electronics.one_access) door.req_one_access = electronics.accesses else diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index 605a48b2e15..e110891ad32 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -140,7 +140,10 @@ set_frequency(frequency) AddElement(/datum/element/connect_loc, atmos_connections) AddComponent(/datum/component/usb_port, list( + /obj/item/circuit_component/air_alarm_general, /obj/item/circuit_component/air_alarm, + /obj/item/circuit_component/air_alarm_scrubbers, + /obj/item/circuit_component/air_alarm_vents )) @@ -550,6 +553,7 @@ "checks" = 2, "set_internal_pressure" = 0 ), signal_source) + SEND_SIGNAL(src, COMSIG_AIRALARM_UPDATE_MODE, signal_source) /obj/machinery/airalarm/update_appearance(updates) . = ..() @@ -914,8 +918,114 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/airalarm, 24) -/obj/item/circuit_component/air_alarm +/obj/item/circuit_component/air_alarm_general display_name = "Air Alarm" + desc = "Outputs basic information that the air alarm has recorded" + + var/obj/machinery/airalarm/connected_alarm + + /// Enables the fire alarm + var/datum/port/input/enable_fire_alarm + /// Disables the fire alarm + var/datum/port/input/disable_fire_alarm + + /// The mode to set the air alarm to + var/datum/port/input/option/mode + /// The trigger to set the mode + var/datum/port/input/set_mode + + /// Whether the fire alarm is enabled or not + var/datum/port/output/fire_alarm_enabled + /// The current set mode + var/datum/port/output/current_mode + + var/static/list/options_map + +/obj/item/circuit_component/air_alarm_general/populate_options() + if(!options_map) + options_map = list( + "Filtering" = AALARM_MODE_SCRUBBING, + "Contaminated" = AALARM_MODE_CONTAMINATED, + "Draught" = AALARM_MODE_VENTING, + "Refill" = AALARM_MODE_REFILL, + "Cycle" = AALARM_MODE_REPLACEMENT, + "Siphon" = AALARM_MODE_SIPHON, + "Panic Siphon" = AALARM_MODE_PANIC, + "Off" = AALARM_MODE_OFF, + ) + +/obj/item/circuit_component/air_alarm_general/populate_ports() + mode = add_option_port("Mode", options_map, order = 1) + set_mode = add_input_port("Set Mode", PORT_TYPE_SIGNAL, trigger = .proc/set_mode) + enable_fire_alarm = add_input_port("Enable Alarm", PORT_TYPE_SIGNAL, trigger = .proc/trigger_alarm) + disable_fire_alarm = add_input_port("Disable Alarm", PORT_TYPE_SIGNAL, trigger = .proc/trigger_alarm) + + fire_alarm_enabled = add_output_port("Alarm Enabled", PORT_TYPE_NUMBER) + current_mode = add_output_port("Current Mode", PORT_TYPE_STRING) + +/obj/item/circuit_component/air_alarm_general/register_usb_parent(atom/movable/shell) + . = ..() + if(istype(shell, /obj/machinery/airalarm)) + connected_alarm = shell + RegisterSignal(connected_alarm.alarm_manager, COMSIG_ALARM_TRIGGERED, .proc/on_alarm_triggered) + RegisterSignal(connected_alarm.alarm_manager, COMSIG_ALARM_CLEARED, .proc/on_alarm_cleared) + RegisterSignal(shell, COMSIG_AIRALARM_UPDATE_MODE, .proc/on_mode_updated) + current_mode.set_value(connected_alarm.get_mode_name(connected_alarm.mode)) + +/obj/item/circuit_component/air_alarm_general/unregister_usb_parent(atom/movable/shell) + if(connected_alarm) + UnregisterSignal(connected_alarm.alarm_manager, list( + COMSIG_ALARM_TRIGGERED, + COMSIG_ALARM_CLEARED, + )) + connected_alarm = null + + UnregisterSignal(shell, list( + COMSIG_AIRALARM_UPDATE_MODE, + )) + return ..() + +/obj/item/circuit_component/air_alarm_general/proc/on_mode_updated(obj/machinery/airalarm/alarm, datum/signal_source) + SIGNAL_HANDLER + current_mode.set_value(alarm.get_mode_name(alarm.mode)) + +/obj/item/circuit_component/air_alarm_general/proc/on_alarm_triggered(datum/source, alarm_type, area/location) + SIGNAL_HANDLER + if(alarm_type == ALARM_ATMOS) + fire_alarm_enabled.set_output(TRUE) + +/obj/item/circuit_component/air_alarm_general/proc/on_alarm_cleared(datum/source, alarm_type, area/location) + SIGNAL_HANDLER + if(alarm_type == ALARM_ATMOS) + fire_alarm_enabled.set_output(FALSE) + + +/obj/item/circuit_component/air_alarm_general/proc/trigger_alarm(datum/port/input/port) + CIRCUIT_TRIGGER + if(!connected_alarm || connected_alarm.locked) + return + + if(port == enable_fire_alarm) + if(connected_alarm.alarm_manager.send_alarm(ALARM_ATMOS)) + INVOKE_ASYNC(connected_alarm, /obj/machinery/airalarm.proc/post_alert, 2) + else + if(connected_alarm.alarm_manager.clear_alarm(ALARM_ATMOS)) + INVOKE_ASYNC(connected_alarm, /obj/machinery/airalarm.proc/post_alert, 0) + +/obj/item/circuit_component/air_alarm_general/proc/set_mode(datum/port/input/port) + CIRCUIT_TRIGGER + if(!connected_alarm || connected_alarm.locked) + return + + if(!mode.value) + return + + connected_alarm.mode = options_map[mode.value] + connected_alarm.investigate_log("was turned to [connected_alarm.get_mode_name(connected_alarm.mode)] by [parent.get_creator()]") + INVOKE_ASYNC(connected_alarm, /obj/machinery/airalarm.proc/apply_mode, src) + +/obj/item/circuit_component/air_alarm + display_name = "Air Alarm Core Control" desc = "Controls levels of gases and their temperature as well as all vents and scrubbers in the room." var/datum/port/input/option/air_alarm_options @@ -925,25 +1035,51 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/airalarm, 24) var/datum/port/input/max_1 var/datum/port/input/max_2 + var/datum/port/input/set_data var/datum/port/input/request_data var/datum/port/output/pressure var/datum/port/output/temperature var/datum/port/output/gas_amount + var/datum/port/output/update_received var/obj/machinery/airalarm/connected_alarm var/list/options_map + ui_buttons = list( + "plus" = "add_new_component" + ) + + var/list/alarm_duplicates = list() + var/max_alarm_duplicates = 20 + +/obj/item/circuit_component/air_alarm/ui_perform_action(mob/user, action) + if(length(alarm_duplicates) >= max_alarm_duplicates) + return + + if(action == "add_new_component") + var/obj/item/circuit_component/air_alarm/component = new /obj/item/circuit_component/air_alarm/duplicate(parent) + parent.add_component(component) + RegisterSignal(component, COMSIG_PARENT_QDELETING, .proc/on_duplicate_removed) + component.connected_alarm = connected_alarm + alarm_duplicates += component + +/obj/item/circuit_component/air_alarm/proc/on_duplicate_removed(datum/source) + SIGNAL_HANDLER + alarm_duplicates -= source + /obj/item/circuit_component/air_alarm/populate_ports() - min_2 = add_input_port("Min 2", PORT_TYPE_NUMBER) - min_1 = add_input_port("Min 1", PORT_TYPE_NUMBER) - max_1 = add_input_port("Max 1", PORT_TYPE_NUMBER) - max_2 = add_input_port("Max 2", PORT_TYPE_NUMBER) - request_data = add_input_port("Request Atmosphere Data", PORT_TYPE_SIGNAL) + min_2 = add_input_port("Hazard Minimum", PORT_TYPE_NUMBER, trigger = null) + min_1 = add_input_port("Warning Minimum", PORT_TYPE_NUMBER, trigger = null) + max_1 = add_input_port("Warning Maximum", PORT_TYPE_NUMBER, trigger = null) + max_2 = add_input_port("Hazard Maximum", PORT_TYPE_NUMBER, trigger = null) + set_data = add_input_port("Set Limits", PORT_TYPE_SIGNAL, trigger = .proc/set_limits) + request_data = add_input_port("Request Data", PORT_TYPE_SIGNAL) pressure = add_output_port("Pressure", PORT_TYPE_NUMBER) temperature = add_output_port("Temperature", PORT_TYPE_NUMBER) gas_amount = add_output_port("Chosen Gas Amount", PORT_TYPE_NUMBER) + update_received = add_output_port("Update Received", PORT_TYPE_SIGNAL) /obj/item/circuit_component/air_alarm/populate_options() var/static/list/component_options @@ -960,6 +1096,25 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/airalarm, 24) air_alarm_options = add_option_port("Air Alarm Options", component_options) options_map = component_options +/obj/item/circuit_component/air_alarm/duplicate + display_name = "Air Alarm Control" + + circuit_size = 0 + ui_buttons = list() + +/obj/item/circuit_component/air_alarm/duplicate/removed_from(obj/item/integrated_circuit/removed_from) + if(!QDELING(src)) + qdel(src) + return ..() + +/obj/item/circuit_component/air_alarm/duplicate/Destroy() + connected_alarm = null + return ..() + +/obj/item/circuit_component/air_alarm/removed_from(obj/item/integrated_circuit/removed_from) + QDEL_LIST(alarm_duplicates) + return ..() + /obj/item/circuit_component/air_alarm/register_usb_parent(atom/movable/shell) . = ..() if(istype(shell, /obj/machinery/airalarm)) @@ -967,28 +1122,534 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/airalarm, 24) /obj/item/circuit_component/air_alarm/unregister_usb_parent(atom/movable/shell) connected_alarm = null + for(var/obj/item/circuit_component/air_alarm/alarm as anything in alarm_duplicates) + alarm.connected_alarm = null return ..() +/obj/item/circuit_component/air_alarm/proc/set_limits() + CIRCUIT_TRIGGER + if(!connected_alarm || connected_alarm.locked) + return + + var/current_option = air_alarm_options.value + + if(!current_option) + return + + var/datum/tlv/settings = connected_alarm.TLV[options_map[current_option]] + if(min_2.value != null) + settings.hazard_min = min_2.value + if(min_1.value != null) + settings.warning_min = min_1.value + if(max_1.value != null) + settings.warning_max = max_1.value + if(max_2.value != null) + settings.hazard_max = max_2.value + /obj/item/circuit_component/air_alarm/input_received(datum/port/input/port) if(!connected_alarm || connected_alarm.locked) return var/current_option = air_alarm_options.value - if(COMPONENT_TRIGGERED_BY(request_data, port)) - var/turf/alarm_turf = get_turf(connected_alarm) - var/datum/gas_mixture/environment = alarm_turf.return_air() - pressure.set_output(round(environment.return_pressure())) - temperature.set_output(round(environment.temperature)) - if(ispath(options_map[current_option])) - gas_amount.set_output(round(environment.gases[options_map[current_option]][MOLES])) + var/turf/alarm_turf = get_turf(connected_alarm) + var/datum/gas_mixture/environment = alarm_turf.return_air() + pressure.set_output(round(environment.return_pressure())) + temperature.set_output(round(environment.temperature)) + if(ispath(options_map[current_option])) + gas_amount.set_output(round(environment.gases[options_map[current_option]][MOLES])) + + update_received.set_output(COMPONENT_SIGNAL) + +/obj/item/circuit_component/air_alarm_scrubbers + display_name = "Air Alarm Scrubber Core Control" + desc = "Controls the scrubbers in the room." + + var/datum/port/input/option/scrubbers + + /// Enables the scrubber + var/datum/port/input/enable + /// Disables the scrubber + var/datum/port/input/disable + + /// Enables siphoning + var/datum/port/input/enable_siphon + /// Disables siphoning + var/datum/port/input/disable_siphon + /// Enables extended range + var/datum/port/input/enable_extended_range + /// Disables extended range + var/datum/port/input/disable_extended_range + /// Gas to filter using the scrubber + var/datum/port/input/gas_filter + /// Sets the filter + var/datum/port/input/set_gas_filter + /// Requests an update of the data + var/datum/port/input/request_update + + + /// Whether the scrubber is enabled or not + var/datum/port/output/enabled + /// Whether the scrubber is siphoning or not + var/datum/port/output/is_siphoning + /// Information based on what the scrubber is filtering. Outputs null if the scrubber is siphoning + var/datum/port/output/filtering + /// Sent when an update is received + var/datum/port/output/update_received + + var/obj/machinery/airalarm/connected_alarm + + ui_buttons = list( + "plus" = "add_new_component" + ) + + var/static/list/filtering_map = list() + + var/max_scrubber_duplicates = 20 + var/list/scrubber_duplicates = list() + +/obj/item/circuit_component/air_alarm_scrubbers/ui_perform_action(mob/user, action) + if(length(scrubber_duplicates) >= max_scrubber_duplicates) return - var/datum/tlv/settings = connected_alarm.TLV[options_map[current_option]] - settings.hazard_min = min_2 - settings.warning_min = min_1 - settings.warning_max = max_1 - settings.hazard_max = max_2 + if(action == "add_new_component") + var/obj/item/circuit_component/air_alarm_scrubbers/component = new /obj/item/circuit_component/air_alarm_scrubbers/duplicate(parent) + parent.add_component(component) + RegisterSignal(component, COMSIG_PARENT_QDELETING, .proc/on_duplicate_removed) + component.connected_alarm = connected_alarm + component.scrubbers.possible_options = connected_alarm.my_area.air_scrub_info + scrubber_duplicates += component + +/obj/item/circuit_component/air_alarm_scrubbers/proc/on_duplicate_removed(datum/source) + SIGNAL_HANDLER + scrubber_duplicates -= source + +/obj/item/circuit_component/air_alarm_scrubbers/populate_options() + scrubbers = add_option_port("Scrubber", null) + +/obj/item/circuit_component/air_alarm_scrubbers/populate_ports() + gas_filter = add_input_port("Gas To Filter", PORT_TYPE_LIST(PORT_TYPE_STRING), trigger = null) + set_gas_filter = add_input_port("Set Filter", PORT_TYPE_SIGNAL, trigger = .proc/set_gas_to_filter) + enable_extended_range = add_input_port("Enable Extra Range", PORT_TYPE_SIGNAL, trigger = .proc/toggle_range) + disable_extended_range = add_input_port("Disable Extra Range", PORT_TYPE_SIGNAL, trigger = .proc/toggle_range) + enable_siphon = add_input_port("Enable Siphon", PORT_TYPE_SIGNAL, trigger = .proc/toggle_siphon) + disable_siphon = add_input_port("Disable Siphon", PORT_TYPE_SIGNAL, trigger = .proc/toggle_siphon) + enable = add_input_port("Enable", PORT_TYPE_SIGNAL, trigger = .proc/toggle_scrubber) + disable = add_input_port("Disable", PORT_TYPE_SIGNAL, trigger = .proc/toggle_scrubber) + request_update = add_input_port("Request Data", PORT_TYPE_SIGNAL, trigger = .proc/update_data) + + enabled = add_output_port("Enabled", PORT_TYPE_NUMBER) + is_siphoning = add_output_port("Siphoning", PORT_TYPE_NUMBER) + filtering = add_output_port("Filtered Gases", PORT_TYPE_LIST(PORT_TYPE_STRING)) + update_received = add_output_port("Update Received", PORT_TYPE_SIGNAL) + +/obj/item/circuit_component/air_alarm_scrubbers/duplicate + display_name = "Air Alarm Scrubber Control" + circuit_size = 0 + ui_buttons = list() + +/obj/item/circuit_component/air_alarm_scrubbers/duplicate/Destroy() + connected_alarm = null + return ..() + +/obj/item/circuit_component/air_alarm_scrubbers/duplicate/removed_from(obj/item/integrated_circuit/removed_from) + if(!QDELING(src)) + qdel(src) + return ..() + +/obj/item/circuit_component/air_alarm_scrubbers/removed_from(obj/item/integrated_circuit/removed_from) + QDEL_LIST(scrubber_duplicates) + return ..() + +/obj/item/circuit_component/air_alarm_scrubbers/register_usb_parent(atom/movable/shell) + . = ..() + if(istype(shell, /obj/machinery/airalarm)) + connected_alarm = shell + scrubbers.possible_options = connected_alarm.my_area.air_scrub_info + +/obj/item/circuit_component/air_alarm_scrubbers/unregister_usb_parent(atom/movable/shell) + connected_alarm = null + scrubbers.possible_options = null + for(var/obj/item/circuit_component/air_alarm_scrubbers/scrubber as anything in scrubber_duplicates) + scrubber.connected_alarm = null + return ..() + +/obj/item/circuit_component/air_alarm_scrubbers/get_ui_notices() + . = ..() + var/static/list/meta_data = list() + if(length(meta_data) == 0) + for(var/typepath as anything in GLOB.meta_gas_info) + meta_data += GLOB.meta_gas_info[typepath][META_GAS_ID] + . += create_table_notices(meta_data, column_name = "Gas", column_name_plural = "Gases") + +/obj/item/circuit_component/air_alarm_scrubbers/proc/set_gas_to_filter(datum/port/input/port) + CIRCUIT_TRIGGER + INVOKE_ASYNC(src, .proc/set_gas_filter_async, port) + +/obj/item/circuit_component/air_alarm_scrubbers/proc/set_gas_filter_async(datum/port/input/port) + if(!connected_alarm || connected_alarm.locked) + return + + var/scrubber_id = scrubbers.value + var/list/valid_filters = list() + for(var/info in gas_filter.value) + if(gas_id2path(info) == "") + continue + valid_filters += info + + connected_alarm.send_signal(scrubber_id, list( + "set_filters" = valid_filters, + )) + +/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_scrubber(datum/port/input/port) + CIRCUIT_TRIGGER + INVOKE_ASYNC(src, .proc/toggle_scrubber_async, port) + +/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_scrubber_async(datum/port/input/port) + if(!connected_alarm || connected_alarm.locked) + return + + var/scrubber_id = scrubbers.value + + if(port == enable) + connected_alarm.send_signal(scrubber_id, list( + "power" = TRUE, + )) + else + connected_alarm.send_signal(scrubber_id, list( + "power" = FALSE, + )) + +/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_range(datum/port/input/port) + CIRCUIT_TRIGGER + INVOKE_ASYNC(src, .proc/toggle_range_async, port) + +/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_range_async(datum/port/input/port) + if(!connected_alarm || connected_alarm.locked) + return + + var/scrubber_id = scrubbers.value + + if(port == enable_extended_range) + connected_alarm.send_signal(scrubber_id, list( + "widenet" = TRUE, + )) + else + connected_alarm.send_signal(scrubber_id, list( + "widenet" = FALSE, + )) + +/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_siphon(datum/port/input/port) + CIRCUIT_TRIGGER + INVOKE_ASYNC(src, .proc/toggle_siphon_async, port) + +/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_siphon_async(datum/port/input/port) + if(!connected_alarm || connected_alarm.locked) + return + + var/scrubber_id = scrubbers.value + + if(port == enable_siphon) + connected_alarm.send_signal(scrubber_id, list( + "scrubbing" = FALSE, + )) + else + connected_alarm.send_signal(scrubber_id, list( + "scrubbing" = TRUE, + )) + +/obj/item/circuit_component/air_alarm_scrubbers/proc/update_data() + CIRCUIT_TRIGGER + if(!connected_alarm || connected_alarm.locked) + return + + var/scrubber_id = scrubbers.value + + var/list/info = connected_alarm.my_area.air_scrub_info[scrubber_id] + if(!info || info["frequency"] != connected_alarm.frequency) + return + + enabled.set_value(info["power"]) + is_siphoning.set_value(!info["scrubbing"]) + + var/list/filtered = list() + + for(var/list/data as anything in info["filter_types"]) + if(data["enabled"]) + filtered += data["gas_id"] + + filtering.set_value(filtered) + + update_received.set_value(COMPONENT_SIGNAL) + +/obj/item/circuit_component/air_alarm_vents + display_name = "Air Alarm Vent Core Control" + desc = "Controls the vents in the room." + + var/datum/port/input/option/vents + + /// Enables the vent + var/datum/port/input/enable + /// Disables the vent + var/datum/port/input/disable + + /// Enables siphoning + var/datum/port/input/enable_siphon + /// Disables siphoning + var/datum/port/input/disable_siphon + /// Enables external + var/datum/port/input/enable_external + /// Disables external + var/datum/port/input/disable_external + /// External target pressure + var/datum/port/input/external_pressure + /// Enables internal + var/datum/port/input/enable_internal + /// Disables internal + var/datum/port/input/disable_internal + /// Internal target pressure + var/datum/port/input/internal_pressure + /// Requests an update of the data + var/datum/port/input/request_update + + + /// Whether the scrubber is enabled or not + var/datum/port/output/enabled + /// Whether the scrubber is siphoning or not + var/datum/port/output/is_siphoning + /// Whether internal pressure is on or not + var/datum/port/output/internal_on + /// Whether external pressure is on or not + var/datum/port/output/external_on + /// Reported external pressure + var/datum/port/output/current_external_pressure + /// Reported internal pressure + var/datum/port/output/current_internal_pressure + /// Sent when an update is received + var/datum/port/output/update_received + + var/obj/machinery/airalarm/connected_alarm + + ui_buttons = list( + "plus" = "add_new_component" + ) + + var/static/list/filtering_map = list() + + var/max_vent_duplicates = 20 + var/list/vent_duplicates = list() + +/obj/item/circuit_component/air_alarm_vents/ui_perform_action(mob/user, action) + if(length(vent_duplicates) >= max_vent_duplicates) + return + + if(action == "add_new_component") + var/obj/item/circuit_component/air_alarm_vents/component = new /obj/item/circuit_component/air_alarm_vents/duplicate(parent) + parent.add_component(component) + RegisterSignal(component, COMSIG_PARENT_QDELETING, .proc/on_duplicate_removed) + vent_duplicates += component + component.connected_alarm = connected_alarm + component.vents.possible_options = connected_alarm.my_area.air_vent_info + +/obj/item/circuit_component/air_alarm_vents/proc/on_duplicate_removed(datum/source) + SIGNAL_HANDLER + vent_duplicates -= source + +/obj/item/circuit_component/air_alarm_vents/populate_options() + vents = add_option_port("Vent", null) + +/obj/item/circuit_component/air_alarm_vents/populate_ports() + external_pressure = add_input_port("External Pressure", PORT_TYPE_NUMBER, trigger = .proc/set_external_pressure) + internal_pressure = add_input_port("Internal Pressure", PORT_TYPE_NUMBER, trigger = .proc/set_internal_pressure) + + enable_external = add_input_port("Enable External", PORT_TYPE_SIGNAL, trigger = .proc/toggle_external) + disable_external = add_input_port("Disable External", PORT_TYPE_SIGNAL, trigger = .proc/toggle_external) + enable_internal = add_input_port("Enable Internal", PORT_TYPE_SIGNAL, trigger = .proc/toggle_internal) + disable_internal = add_input_port("Disable Internal", PORT_TYPE_SIGNAL, trigger = .proc/toggle_internal) + + enable_siphon = add_input_port("Enable Siphon", PORT_TYPE_SIGNAL, trigger = .proc/toggle_siphon) + disable_siphon = add_input_port("Disable Siphon", PORT_TYPE_SIGNAL, trigger = .proc/toggle_siphon) + enable = add_input_port("Enable", PORT_TYPE_SIGNAL, trigger = .proc/toggle_vent) + disable = add_input_port("Disable", PORT_TYPE_SIGNAL, trigger = .proc/toggle_vent) + request_update = add_input_port("Request Data", PORT_TYPE_SIGNAL, trigger = .proc/update_data) + + enabled = add_output_port("Enabled", PORT_TYPE_NUMBER) + is_siphoning = add_output_port("Siphoning", PORT_TYPE_NUMBER) + external_on = add_output_port("External On", PORT_TYPE_NUMBER) + internal_on = add_output_port("Internal On", PORT_TYPE_NUMBER) + current_external_pressure = add_output_port("External Pressure", PORT_TYPE_NUMBER) + current_internal_pressure = add_output_port("Internal Pressure", PORT_TYPE_NUMBER) + update_received = add_output_port("Update Received", PORT_TYPE_SIGNAL) + +/obj/item/circuit_component/air_alarm_vents/duplicate + display_name = "Air Alarm Vent Control" + + circuit_size = 0 + ui_buttons = list() + +/obj/item/circuit_component/air_alarm_vents/duplicate/removed_from(obj/item/integrated_circuit/removed_from) + if(!QDELING(src)) + qdel(src) + return ..() + +/obj/item/circuit_component/air_alarm_vents/duplicate/Destroy() + connected_alarm = null + return ..() + +/obj/item/circuit_component/air_alarm_vents/removed_from(obj/item/integrated_circuit/removed_from) + QDEL_LIST(vent_duplicates) + return ..() + +/obj/item/circuit_component/air_alarm_vents/register_usb_parent(atom/movable/shell) + . = ..() + if(istype(shell, /obj/machinery/airalarm)) + connected_alarm = shell + vents.possible_options = connected_alarm.my_area.air_vent_info + +/obj/item/circuit_component/air_alarm_vents/unregister_usb_parent(atom/movable/shell) + connected_alarm = null + vents.possible_options = null + for(var/obj/item/circuit_component/air_alarm_vents/vent as anything in vent_duplicates) + vent.connected_alarm = null + return ..() + +/obj/item/circuit_component/air_alarm_vents/proc/toggle_vent(datum/port/input/port) + CIRCUIT_TRIGGER + INVOKE_ASYNC(src, .proc/toggle_vent_async, port) + +/obj/item/circuit_component/air_alarm_vents/proc/toggle_vent_async(datum/port/input/port) + if(!connected_alarm || connected_alarm.locked) + return + + var/vent_id = vents.value + + if(port == enable) + connected_alarm.send_signal(vent_id, list( + "power" = TRUE, + )) + else + connected_alarm.send_signal(vent_id, list( + "power" = FALSE, + )) + +#define EXT_BOUND 1 +#define INT_BOUND 2 +#define NO_BOUND 3 + +/obj/item/circuit_component/air_alarm_vents/proc/toggle_external(datum/port/input/port) + CIRCUIT_TRIGGER + INVOKE_ASYNC(src, .proc/toggle_external_async, port) + +/obj/item/circuit_component/air_alarm_vents/proc/toggle_external_async(datum/port/input/port) + if(!connected_alarm || connected_alarm.locked) + return + + var/vent_id = vents.value + var/list/info = connected_alarm.my_area.air_vent_info[vent_id] + if(!info || info["frequency"] != connected_alarm.frequency) + return + + if(port == enable_external) + connected_alarm.send_signal(vent_id, list( + "checks" = (info["checks"] | EXT_BOUND), + )) + else + connected_alarm.send_signal(vent_id, list( + "checks" = (info["checks"] & ~EXT_BOUND), + )) + +/obj/item/circuit_component/air_alarm_vents/proc/toggle_internal(datum/port/input/port) + CIRCUIT_TRIGGER + INVOKE_ASYNC(src, .proc/toggle_internal_async, port) + +/obj/item/circuit_component/air_alarm_vents/proc/toggle_internal_async(datum/port/input/port) + if(!connected_alarm || connected_alarm.locked) + return + + var/vent_id = vents.value + var/list/info = connected_alarm.my_area.air_vent_info[vent_id] + if(!info || info["frequency"] != connected_alarm.frequency) + return + + if(port == enable_internal) + connected_alarm.send_signal(vent_id, list( + "checks" = (info["checks"] | INT_BOUND), + )) + else + connected_alarm.send_signal(vent_id, list( + "checks" = (info["checks"] & ~INT_BOUND), + )) + +/obj/item/circuit_component/air_alarm_vents/proc/set_internal_pressure(datum/port/input/port) + CIRCUIT_TRIGGER + INVOKE_ASYNC(src, .proc/set_internal_pressure_async, port) + +/obj/item/circuit_component/air_alarm_vents/proc/set_internal_pressure_async(datum/port/input/port) + if(!connected_alarm || connected_alarm.locked) + return + + var/vent_id = vents.value + + connected_alarm.send_signal(vent_id, list( + "set_internal_pressure" = internal_pressure.value || 0, + )) + +/obj/item/circuit_component/air_alarm_vents/proc/set_external_pressure(datum/port/input/port) + CIRCUIT_TRIGGER + INVOKE_ASYNC(src, .proc/set_external_pressure_async, port) + +/obj/item/circuit_component/air_alarm_vents/proc/set_external_pressure_async(datum/port/input/port) + if(!connected_alarm || connected_alarm.locked) + return + + var/vent_id = vents.value + + connected_alarm.send_signal(vent_id, list( + "set_external_pressure" = external_pressure.value || 0, + )) + + +/obj/item/circuit_component/air_alarm_vents/proc/toggle_siphon(datum/port/input/port) + CIRCUIT_TRIGGER + INVOKE_ASYNC(src, .proc/toggle_siphon_async, port) + +/obj/item/circuit_component/air_alarm_vents/proc/toggle_siphon_async(datum/port/input/port) + if(!connected_alarm || connected_alarm.locked) + return + + var/scrubber_id = vents.value + + if(port == enable_siphon) + connected_alarm.send_signal(scrubber_id, list( + "direction" = FALSE, + )) + else + connected_alarm.send_signal(scrubber_id, list( + "direction" = TRUE, + )) + +/obj/item/circuit_component/air_alarm_vents/proc/update_data() + CIRCUIT_TRIGGER + if(!connected_alarm || connected_alarm.locked) + return + + var/vent_id = vents.value + + var/list/info = connected_alarm.my_area.air_vent_info[vent_id] + if(!info || info["frequency"] != connected_alarm.frequency) + return + + enabled.set_value(info["power"]) + is_siphoning.set_value(!info["direction"]) + internal_on.set_value(!!(info["checks"] & INT_BOUND)) + current_internal_pressure.set_value(info["internal"]) + external_on.set_value(!!(info["checks"] & EXT_BOUND)) + current_external_pressure.set_value(info["external"]) + update_received.set_value(COMPONENT_SIGNAL) + +#undef EXT_BOUND +#undef INT_BOUND +#undef NO_BOUND #undef AALARM_MODE_SCRUBBING #undef AALARM_MODE_VENTING diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 6a2daababe7..50e47464329 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -196,8 +196,8 @@ ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, ROUNDSTART_TRAIT) alert_control = new(src, list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER, ALARM_CAMERA, ALARM_BURGLAR, ALARM_MOTION), list(z), camera_view = TRUE) - RegisterSignal(alert_control.listener, COMSIG_ALARM_TRIGGERED, .proc/alarm_triggered) - RegisterSignal(alert_control.listener, COMSIG_ALARM_CLEARED, .proc/alarm_cleared) + RegisterSignal(alert_control.listener, COMSIG_ALARM_LISTENER_TRIGGERED, .proc/alarm_triggered) + RegisterSignal(alert_control.listener, COMSIG_ALARM_LISTENER_CLEARED, .proc/alarm_cleared) /mob/living/silicon/ai/key_down(_key, client/user) if(findtext(_key, "numpad")) //if it's a numpad number, we can convert it to just the number diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index fd1abfee162..7db855b363a 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -80,8 +80,8 @@ diag_hud_set_borgcell() logevent("System brought online.") alert_control = new(src, list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER, ALARM_CAMERA, ALARM_BURGLAR, ALARM_MOTION), list(z)) - RegisterSignal(alert_control.listener, COMSIG_ALARM_TRIGGERED, .proc/alarm_triggered) - RegisterSignal(alert_control.listener, COMSIG_ALARM_CLEARED, .proc/alarm_cleared) + RegisterSignal(alert_control.listener, COMSIG_ALARM_LISTENER_TRIGGERED, .proc/alarm_triggered) + RegisterSignal(alert_control.listener, COMSIG_ALARM_LISTENER_CLEARED, .proc/alarm_cleared) alert_control.listener.RegisterSignal(src, COMSIG_LIVING_DEATH, /datum/alarm_listener/proc/prevent_alarm_changes) alert_control.listener.RegisterSignal(src, COMSIG_LIVING_REVIVE, /datum/alarm_listener/proc/allow_alarm_changes) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index 5df42a47290..a0d565c253c 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -189,8 +189,8 @@ ADD_TRAIT(src, TRAIT_LITERATE, INNATE_TRAIT) listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER), list(z)) - RegisterSignal(listener, COMSIG_ALARM_TRIGGERED, .proc/alarm_triggered) - RegisterSignal(listener, COMSIG_ALARM_CLEARED, .proc/alarm_cleared) + RegisterSignal(listener, COMSIG_ALARM_LISTENER_TRIGGERED, .proc/alarm_triggered) + RegisterSignal(listener, COMSIG_ALARM_LISTENER_CLEARED, .proc/alarm_cleared) listener.RegisterSignal(src, COMSIG_LIVING_DEATH, /datum/alarm_listener/proc/prevent_alarm_changes) listener.RegisterSignal(src, COMSIG_LIVING_REVIVE, /datum/alarm_listener/proc/allow_alarm_changes) diff --git a/code/modules/modular_computers/file_system/programs/alarm.dm b/code/modules/modular_computers/file_system/programs/alarm.dm index 264fefbb737..b658e34286d 100644 --- a/code/modules/modular_computers/file_system/programs/alarm.dm +++ b/code/modules/modular_computers/file_system/programs/alarm.dm @@ -19,7 +19,7 @@ //Or if we're on station. Otherwise, die. var/list/allowed_areas = GLOB.the_station_areas + typesof(/area/mine) alert_control = new(computer, list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER), listener_areas = allowed_areas) - RegisterSignal(alert_control.listener, list(COMSIG_ALARM_TRIGGERED, COMSIG_ALARM_CLEARED), .proc/update_alarm_display) + RegisterSignal(alert_control.listener, list(COMSIG_ALARM_LISTENER_TRIGGERED, COMSIG_ALARM_LISTENER_CLEARED), .proc/update_alarm_display) return ..() /datum/computer_file/program/alarm_monitor/Destroy() diff --git a/code/modules/wiremod/core/component.dm b/code/modules/wiremod/core/component.dm index 670fde7f09f..bfdf9b62b8b 100644 --- a/code/modules/wiremod/core/component.dm +++ b/code/modules/wiremod/core/component.dm @@ -373,15 +373,15 @@ * Returns a list that can then be added to the return list in get_ui_notices() * Used by components to list their available columns. Recommended to use at the end of get_ui_notices() */ -/obj/item/circuit_component/proc/create_table_notices(list/entries) +/obj/item/circuit_component/proc/create_table_notices(list/entries, column_name = "Column", column_name_plural = "Columns") SHOULD_BE_PURE(TRUE) SHOULD_NOT_OVERRIDE(TRUE) . = list() - . += create_ui_notice("Available Columns:", "grey", "question-circle") + . += create_ui_notice("Available [column_name_plural]:", "grey", "question-circle") for(var/entry in entries) - . += create_ui_notice("Column Name: '[entry]'", "grey", "columns") + . += create_ui_notice("[column_name] Name: '[entry]'", "grey", "columns") /** * Called when a circuit component is added to an object with a USB port. diff --git a/code/modules/wiremod/core/integrated_circuit.dm b/code/modules/wiremod/core/integrated_circuit.dm index f0b96d32d50..99dce57c0b6 100644 --- a/code/modules/wiremod/core/integrated_circuit.dm +++ b/code/modules/wiremod/core/integrated_circuit.dm @@ -221,13 +221,13 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit) */ /obj/item/integrated_circuit/proc/add_component(obj/item/circuit_component/to_add, mob/living/user) if(to_add.parent) - return + return FALSE if(SEND_SIGNAL(src, COMSIG_CIRCUIT_ADD_COMPONENT, to_add, user) & COMPONENT_CANCEL_ADD_COMPONENT) - return + return FALSE if(!to_add.add_to(src)) - return + return FALSE var/success = FALSE if(user) @@ -236,7 +236,7 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit) success = to_add.forceMove(src) if(!success) - return + return FALSE to_add.rel_x = rand(COMPONENT_MIN_RANDOM_POS, COMPONENT_MAX_RANDOM_POS) - screen_x to_add.rel_y = rand(COMPONENT_MIN_RANDOM_POS, COMPONENT_MAX_RANDOM_POS) - screen_y diff --git a/code/modules/wiremod/shell/airlock.dm b/code/modules/wiremod/shell/airlock.dm index b88740175f2..eabb37ccfa2 100644 --- a/code/modules/wiremod/shell/airlock.dm +++ b/code/modules/wiremod/shell/airlock.dm @@ -193,4 +193,4 @@ return if(result["should_open"]) - return COMPONENT_AIRLOCK_SHELL_ALLOW + return COMPONENT_AIRLOCK_SHELL_ALLOW diff --git a/tgui/packages/tgui/interfaces/AirlockElectronics.tsx b/tgui/packages/tgui/interfaces/AirlockElectronics.tsx index 507440f2ef2..0ed9ef08ad7 100644 --- a/tgui/packages/tgui/interfaces/AirlockElectronics.tsx +++ b/tgui/packages/tgui/interfaces/AirlockElectronics.tsx @@ -11,6 +11,7 @@ type Data = { passedCycleId: number; regions: string[]; accesses: string[]; + shell: BooleanLike; }; export const AirlockElectronics = (props, context) => { @@ -22,6 +23,7 @@ export const AirlockElectronics = (props, context) => { passedCycleId, regions = [], unres_direction, + shell, } = data; return ( @@ -29,6 +31,16 @@ export const AirlockElectronics = (props, context) => {
+ + { + act('set_shell', { on: !shell }); + }} + tooltip="Whether this airlock can have an integrated circuit placed inside of it or not." + /> +