diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm index 6b924ef082..17a2544850 100644 --- a/code/_helpers/game.dm +++ b/code/_helpers/game.dm @@ -246,7 +246,7 @@ var/turf/speaker = get_turf(R) if(speaker) for(var/turf/T in hear(R.canhear_range,speaker)) - speaker_coverage[T] = T + speaker_coverage[T] = R // Try to find all the players who can hear the message diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index d62d53a551..bdd2b05fc6 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -219,6 +219,7 @@ var/on_enter_occupant_message = "You feel cool air surround you. You go numb as your senses turn inward." var/on_store_visible_message_1 = "hums and hisses as it moves" //We need two variables because byond doesn't let us have variables inside strings at compile-time. var/on_store_visible_message_2 = "into storage." + var/announce_channel = "Common" var/allow_occupant_types = list(/mob/living/carbon/human) var/disallow_occupant_types = list() @@ -519,7 +520,7 @@ control_computer._admin_logs += "[key_name(to_despawn)] ([to_despawn.mind.role_alt_title]) at [stationtime2text()]" log_and_message_admins("[key_name(to_despawn)] ([to_despawn.mind.role_alt_title]) entered cryostorage.") - announce.autosay("[to_despawn.real_name], [to_despawn.mind.role_alt_title], [on_store_message]", "[on_store_name]") + announce.autosay("[to_despawn.real_name], [to_despawn.mind.role_alt_title], [on_store_message]", "[on_store_name]", announce_channel, using_map.get_map_levels(z, TRUE)) //visible_message("\The [initial(name)] hums and hisses as it moves [to_despawn.real_name] into storage.", 3) visible_message("\The [initial(name)] [on_store_visible_message_1] [to_despawn.real_name] [on_store_visible_message_2].", 3) diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index 057a8fd5c1..f392eb5218 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -23,6 +23,12 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept produces_heat = 0 delay = 7 circuit = /obj/item/weapon/circuitboard/telecomms/broadcaster + //Vars only used if you're using the overmap + var/overmap_range = 0 + var/overmap_range_min = 0 + var/overmap_range_max = 5 + //Linked bluespace radios + var/list/linked_radios_weakrefs = list() /obj/machinery/telecomms/processor/Initialize() . = ..() @@ -34,6 +40,11 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept component_parts += new /obj/item/weapon/stock_parts/micro_laser/high(src) component_parts += new /obj/item/stack/cable_coil(src, 1) +/obj/machinery/telecomms/broadcaster/proc/link_radio(var/obj/item/device/radio/R) + if(!istype(R)) + return + linked_radios_weakrefs |= weakref(R) + /obj/machinery/telecomms/broadcaster/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) // Don't broadcast rejected signals if(signal.data["reject"]) @@ -58,46 +69,51 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept if(signal.data["slow"] > 0) sleep(signal.data["slow"]) // simulate the network lag if necessary - signal.data["level"] |= listening_level + signal.data["level"] |= using_map.get_map_levels(listening_level, TRUE, overmap_range) + + var/list/forced_radios + for(var/weakref/wr in linked_radios_weakrefs) + var/obj/item/device/radio/R = wr.resolve() + if(istype(R)) + LAZYDISTINCTADD(forced_radios, R) /** #### - Normal Broadcast - #### **/ - - if(signal.data["type"] == 0) - + if(signal.data["type"] == SIGNAL_NORMAL) /* ###### Broadcast a message using signal.data ###### */ Broadcast_Message(signal.data["connection"], signal.data["mob"], signal.data["vmask"], signal.data["vmessage"], signal.data["radio"], signal.data["message"], signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"],, + signal.data["realname"], signal.data["vname"], DATA_NORMAL, signal.data["compression"], signal.data["level"], signal.frequency, - signal.data["verb"], signal.data["language"] ) + signal.data["verb"], signal.data["language"], forced_radios) /** #### - Simple Broadcast - #### **/ - if(signal.data["type"] == 1) + if(signal.data["type"] == SIGNAL_SIMPLE) /* ###### Broadcast a message using signal.data ###### */ Broadcast_SimpleMessage(signal.data["name"], signal.frequency, - signal.data["message"],null, null, - signal.data["compression"], listening_level) + signal.data["message"], DATA_NORMAL, null, + signal.data["compression"], listening_level, forced_radios) /** #### - Artificial Broadcast - #### **/ // (Imitates a mob) - if(signal.data["type"] == 2) + if(signal.data["type"] == SIGNAL_FAKE) /* ###### Broadcast a message using signal.data ###### */ - // Parameter "data" as 4: AI can't track this person/mob + // Parameter "data" as DATA_FAKE: AI can't track this person/mob Broadcast_Message(signal.data["connection"], signal.data["mob"], signal.data["vmask"], signal.data["vmessage"], signal.data["radio"], signal.data["message"], signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"], 4, signal.data["compression"], signal.data["level"], signal.frequency, - signal.data["verb"], signal.data["language"]) + signal.data["realname"], signal.data["vname"], DATA_FAKE, + signal.data["compression"], signal.data["level"], signal.frequency, + signal.data["verb"], signal.data["language"], forced_radios) if(!message_delay) message_delay = 1 @@ -118,6 +134,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* Basically just an empty shell for receiving and broadcasting radio messages. Not very flexible, but it gets the job done. + NOTE: This AIO device listens on *every* zlevel (it does not even check) */ /obj/machinery/telecomms/allinone @@ -126,15 +143,98 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept icon_state = "comm_server" desc = "A compact machine used for portable subspace telecommuniations processing." density = 1 + use_power = USE_POWER_IDLE + idle_power_usage = 20 anchored = 1 - use_power = USE_POWER_OFF - idle_power_usage = 0 machinetype = 6 produces_heat = 0 var/intercept = 0 // if nonzero, broadcasts all messages to syndicate channel + var/overmap_range = 0 //Same turf + + var/list/linked_radios_weakrefs = list() + +/obj/machinery/telecomms/allinone/proc/link_radio(var/obj/item/device/radio/R) + if(!istype(R)) + return + linked_radios_weakrefs |= weakref(R) /obj/machinery/telecomms/allinone/receive_signal(datum/signal/signal) + // Has to be on to receive messages + if(!on) + return + + // Why did you use this subtype? + if(!using_map.use_overmap) + return + + // Someone else handling it? + if(signal.data["done"]) + return + + // Where are we able to hear from (and talk to, since we're AIO) anyway? + var/map_levels = using_map.get_map_levels(z, TRUE, overmap_range) + + //Bluespace can skip this check + if(signal.transmission_method != TRANSMISSION_BLUESPACE) + var/list/signal_levels = list() + signal_levels += signal.data["level"] //If it's text/number, it'll be the only entry, if it's a list, it'll get combined + var/list/overlap = map_levels & signal_levels //Returns a list of similar levels + if(!overlap.len) + return + + if(is_freq_listening(signal)) // detect subspace signals + + signal.data["done"] = 1 // mark the signal as being broadcasted since we're a broadcaster + signal.data["compression"] = 0 // decompress since we're a processor + + // Search for the original signal and mark it as done as well + var/datum/signal/original = signal.data["original"] + if(original) + original.data["done"] = 1 + + // For some reason level is both used as a list and not a list, and now it needs to be a list. + signal.data["level"] = map_levels + + if(signal.data["slow"] > 0) + sleep(signal.data["slow"]) // simulate the network lag if necessary + + /* ###### Broadcast a message using signal.data ###### */ + + var/datum/radio_frequency/connection = signal.data["connection"] + + var/list/forced_radios + for(var/weakref/wr in linked_radios_weakrefs) + var/obj/item/device/radio/R = wr.resolve() + if(istype(R)) + LAZYDISTINCTADD(forced_radios, R) + + Broadcast_Message( + signal.data["connection"], + signal.data["mob"], + signal.data["vmask"], + signal.data["vmessage"], + signal.data["radio"], + signal.data["message"], + signal.data["name"], + signal.data["job"], + signal.data["realname"], + signal.data["vname"], + DATA_NORMAL, + signal.data["compression"], + signal.data["level"], + connection.frequency, + signal.data["verb"], + signal.data["language"], + forced_radios + ) + +//Antag version with unlimited range (doesn't even check) and uses no power, to enable antag comms to work anywhere. +/obj/machinery/telecomms/allinone/antag + use_power = USE_POWER_OFF + idle_power_usage = 0 + +/obj/machinery/telecomms/allinone/antag/receive_signal(datum/signal/signal) if(!on) // has to be on to receive messages return @@ -159,23 +259,29 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept var/datum/radio_frequency/connection = signal.data["connection"] + var/list/forced_radios + for(var/weakref/wr in linked_radios_weakrefs) + var/obj/item/device/radio/R = wr.resolve() + if(istype(R)) + LAZYDISTINCTADD(forced_radios, R) + if(connection.frequency in ANTAG_FREQS) // if antag broadcast, just Broadcast_Message(signal.data["connection"], signal.data["mob"], signal.data["vmask"], signal.data["vmessage"], signal.data["radio"], signal.data["message"], signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"],, signal.data["compression"], list(0), connection.frequency, - signal.data["verb"], signal.data["language"]) + signal.data["realname"], signal.data["vname"], DATA_NORMAL, + signal.data["compression"], list(0), connection.frequency, + signal.data["verb"], signal.data["language"], forced_radios) else if(intercept) Broadcast_Message(signal.data["connection"], signal.data["mob"], signal.data["vmask"], signal.data["vmessage"], signal.data["radio"], signal.data["message"], signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"], 3, signal.data["compression"], list(0), connection.frequency, - signal.data["verb"], signal.data["language"]) - - + signal.data["realname"], signal.data["vname"], DATA_ANTAG, + signal.data["compression"], list(0), connection.frequency, + signal.data["verb"], signal.data["language"], forced_radios) /** @@ -237,7 +343,8 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /proc/Broadcast_Message(var/datum/radio_frequency/connection, var/mob/M, var/vmask, var/vmessage, var/obj/item/device/radio/radio, var/message, var/name, var/job, var/realname, var/vname, - var/data, var/compression, var/list/level, var/freq, var/verbage = "says", var/datum/language/speaking = null) + var/data, var/compression, var/list/level, var/freq, var/verbage = "says", + var/datum/language/speaking = null, var/list/forced_radios) /* ###### Prepare the radio connection ###### */ @@ -246,17 +353,22 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept var/list/obj/item/device/radio/radios = list() + for(var/obj/item/device/radio/R in forced_radios) + //Cursory check to ensure they are 'on' and stuff + if(R.receive_range(display_freq, list(0))) + radios |= R + // --- Broadcast only to intercom devices --- - if(data == 1) + if(data == DATA_INTERCOM) for (var/obj/item/device/radio/intercom/R in connection.devices["[RADIO_CHAT]"]) if(R.receive_range(display_freq, level) > -1) - radios += R + radios |= R // --- Broadcast only to intercoms and station-bounced radios --- - else if(data == 2) + else if(data == DATA_LOCAL) for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"]) @@ -264,16 +376,16 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept continue if(R.receive_range(display_freq, level) > -1) - radios += R + radios |= R // --- Broadcast to antag radios! --- - else if(data == 3) + else if(data == DATA_ANTAG) for(var/antag_freq in ANTAG_FREQS) var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(antag_freq) for (var/obj/item/device/radio/R in antag_connection.devices["[RADIO_CHAT]"]) if(R.receive_range(antag_freq, level) > -1) - radios += R + radios |= R // --- Broadcast to ALL radio devices --- @@ -281,7 +393,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"]) if(R.receive_range(display_freq, level) > -1) - radios += R + radios |= R // Get a list of mobs who can hear from the radios we collected. var/list/receive = get_mobs_in_radio_ranges(radios) @@ -307,7 +419,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept continue // Ghosts hearing all radio chat don't want to hear syndicate intercepts, they're duplicates - if(data == 3 && istype(R, /mob/observer/dead) && R.is_preference_enabled(/datum/client_preference/ghost_radio)) + if(data == DATA_ANTAG && istype(R, /mob/observer/dead) && R.is_preference_enabled(/datum/client_preference/ghost_radio)) continue // --- Check for compression --- @@ -346,7 +458,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept var/freq_text = get_frequency_name(display_freq) var/part_b_extra = "" - if(data == 3) // intercepted radio message + if(data == DATA_ANTAG) // intercepted radio message part_b_extra = " (Intercepted)" var/part_a = "[bicon(radio)]\[[freq_text]\][part_b_extra] " // goes in the actual output @@ -438,7 +550,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept return 1 -/proc/Broadcast_SimpleMessage(var/source, var/frequency, var/text, var/data, var/mob/M, var/compression, var/level) +/proc/Broadcast_SimpleMessage(var/source, var/frequency, var/text, var/data, var/mob/M, var/compression, var/level, var/list/forced_radios) /* ###### Prepare the radio connection ###### */ @@ -452,10 +564,12 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept var/list/receive = list() + for(var/obj/item/device/radio/R in forced_radios) + receive |= R.send_hear(display_freq) // --- Broadcast only to intercom devices --- - if(data == 1) + if(data == DATA_INTERCOM) for (var/obj/item/device/radio/intercom/R in connection.devices["[RADIO_CHAT]"]) var/turf/position = get_turf(R) if(position && position.z == level) @@ -464,7 +578,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept // --- Broadcast only to intercoms and station-bounced radios --- - else if(data == 2) + else if(data == DATA_LOCAL) for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"]) if(istype(R, /obj/item/device/radio/headset)) @@ -476,7 +590,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept // --- Broadcast to antag radios! --- - else if(data == 3) + else if(data == DATA_ANTAG) for(var/freq in ANTAG_FREQS) var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(freq) for (var/obj/item/device/radio/R in antag_connection.devices["[RADIO_CHAT]"]) @@ -541,7 +655,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept // --- Some more pre-message formatting --- var/part_b_extra = "" - if(data == 3) // intercepted radio message + if(data == DATA_ANTAG) // intercepted radio message part_b_extra = " (Intercepted)" // Create a radio headset for the sole purpose of using its icon @@ -617,15 +731,15 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /atom/proc/test_telecomms() var/datum/signal/signal = src.telecomms_process() - var/turf/position = get_turf(src) - return (position.z in signal.data["level"] && signal.data["done"]) + var/pos_z = get_z(src) + return (pos_z in signal.data["level"] && signal.data["done"]) /atom/proc/telecomms_process(var/do_sleep = 1) // First, we want to generate a new radio signal var/datum/signal/signal = new - signal.transmission_method = 2 // 2 would be a subspace transmission. - var/turf/pos = get_turf(src) + signal.transmission_method = TRANSMISSION_SUBSPACE + var/pos_z = get_z(src) // --- Finally, tag the actual signal with the appropriate values --- signal.data = list( @@ -633,10 +747,10 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept "message" = "TEST", "compression" = rand(45, 50), // If the signal is compressed, compress our message too. "traffic" = 0, // dictates the total traffic sum that the signal went through - "type" = 4, // determines what type of radio input it is: test broadcast + "type" = SIGNAL_TEST, // determines what type of radio input it is: test broadcast "reject" = 0, "done" = 0, - "level" = pos.z // The level it is being broadcasted at. + "level" = pos_z // The level it is being broadcasted at. ) signal.frequency = PUB_FREQ// Common channel diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index 3e3d89643a..802c75bb42 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -219,6 +219,38 @@ temp = "-% Frequency changing deactivated %-" +// BROADCASTER +/obj/machinery/telecomms/broadcaster/Options_Menu() + // Note the machine 'displays' 1 higher than overmap_range to save users from the abstraction that range '0' is valid and everything on the same turf. + var/dat = "
Broadcast Range (affects power usage)
- [overmap_range+1] gigameter\s +" + return dat + +/obj/machinery/telecomms/broadcaster/Options_Topic(href, href_list) + if(href_list["range_down"]) + if(overmap_range > overmap_range_min) + overmap_range-- + idle_power_usage = initial(idle_power_usage)**(overmap_range+1) + if(href_list["range_up"]) + if(overmap_range < overmap_range_max) + overmap_range++ + idle_power_usage = initial(idle_power_usage)**(overmap_range+1) + +// RECEIVER +/obj/machinery/telecomms/receiver/Options_Menu() + // Note the machine 'displays' 1 higher than overmap_range to save users from the abstraction that range '0' is valid and everything on the same turf. + var/dat = "
Receive Range (affects power usage)
- [overmap_range+1] gigameter\s +" + return dat + +/obj/machinery/telecomms/receiver/Options_Topic(href, href_list) + if(href_list["range_down"]) + if(overmap_range > overmap_range_min) + overmap_range-- + idle_power_usage = initial(idle_power_usage)**(overmap_range+1) + if(href_list["range_up"]) + if(overmap_range < overmap_range_max) + overmap_range++ + idle_power_usage = initial(idle_power_usage)**(overmap_range+1) + /obj/machinery/telecomms/Topic(href, href_list) if(!issilicon(usr)) diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index c2e9126fc1..38f1adbdfc 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -68,7 +68,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() var/datum/signal/copy if(copysig) copy = new - copy.transmission_method = 2 + copy.transmission_method = TRANSMISSION_SUBSPACE copy.frequency = signal.frequency copy.data = signal.data.Copy() @@ -141,9 +141,9 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() // Used in auto linking /obj/machinery/telecomms/proc/add_link(var/obj/machinery/telecomms/T) - var/turf/position = get_turf(src) - var/turf/T_position = get_turf(T) - if((position.z == T_position.z) || (src.long_range_link && T.long_range_link)) + var/pos_z = get_z(src) + var/tpos_z = get_z(T) + if((pos_z == tpos_z) || (src.long_range_link && T.long_range_link)) for(var/x in autolinkers) if(T.autolinkers.Find(x)) if(src != T) @@ -256,6 +256,12 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() machinetype = 1 produces_heat = 0 circuit = /obj/item/weapon/circuitboard/telecomms/receiver + //Vars only used if you're using the overmap + var/overmap_range = 0 + var/overmap_range_min = 0 + var/overmap_range_max = 5 + + var/list/linked_radios_weakrefs = list() /obj/machinery/telecomms/receiver/Initialize() . = ..() @@ -267,8 +273,12 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) RefreshParts() -/obj/machinery/telecomms/receiver/receive_signal(datum/signal/signal) +/obj/machinery/telecomms/receiver/proc/link_radio(var/obj/item/device/radio/R) + if(!istype(R)) + return + linked_radios_weakrefs |= weakref(R) +/obj/machinery/telecomms/receiver/receive_signal(datum/signal/signal) if(!on) // has to be on to receive messages return if(!signal) @@ -276,7 +286,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() if(!check_receive_level(signal)) return - if(signal.transmission_method == 2) + if(signal.transmission_method == TRANSMISSION_SUBSPACE) if(is_freq_listening(signal)) // detect subspace signals @@ -288,14 +298,31 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() relay_information(signal, "/obj/machinery/telecomms/bus") // Send it to a bus instead, if it's linked to one /obj/machinery/telecomms/receiver/proc/check_receive_level(datum/signal/signal) + // If it's a direct message from a bluespace radio, we eat it and convert it into a subspace signal locally + if(signal.transmission_method == TRANSMISSION_BLUESPACE) + var/obj/item/device/radio/R = signal.data["radio"] - if(signal.data["level"] != listening_level) + //Who're you? + if(!(weakref(R) in linked_radios_weakrefs)) + signal.data["reject"] = 1 + return 0 + + //We'll resend this for you + signal.data["level"] = z + signal.transmission_method = TRANSMISSION_SUBSPACE + return 1 + + //Where can we hear? + var/list/listening_levels = using_map.get_map_levels(listening_level, TRUE, overmap_range) + + // We couldn't 'hear' it, maybe a relay linked to our hub can 'hear' it + if(!(signal.data["level"] in listening_levels)) for(var/obj/machinery/telecomms/hub/H in links) - var/list/connected_levels = list() + var/list/relayed_levels = list() for(var/obj/machinery/telecomms/relay/R in H.links) if(R.can_receive(signal)) - connected_levels |= R.listening_level - if(signal.data["level"] in connected_levels) + relayed_levels |= R.listening_level + if(signal.data["level"] in relayed_levels) return 1 return 0 return 1 @@ -405,7 +432,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() // Add our level and send it back if(can_send(signal)) - signal.data["level"] |= listening_level + signal.data["level"] |= using_map.get_map_levels(listening_level) // Checks to see if it can send/receive. @@ -602,7 +629,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() totaltraffic += traffic // add current traffic to total traffic //Is this a test signal? Bypass logging - if(signal.data["type"] != 4) + if(signal.data["type"] != SIGNAL_TEST) // If signal has a message and appropriate frequency diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 278d911f0e..69b5192abb 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -52,6 +52,13 @@ var/global/list/default_medbay_channels = list( w_class = ITEMSIZE_SMALL show_messages = 1 + // Bluespace radios talk directly to telecomms equipment + var/bluespace_radio = FALSE + var/weakref/bs_tx_weakref //Maybe misleading, this is the device to TRANSMIT TO + // For mappers or subtypes, to start them prelinked to these devices + var/bs_tx_preload_id + var/bs_rx_preload_id + matter = list("glass" = 25,DEFAULT_WALL_MATERIAL = 75) var/const/FREQ_LISTENING = 1 var/list/internal_channels @@ -90,6 +97,43 @@ var/global/list/default_medbay_channels = list( for (var/ch_name in channels) secure_radio_connections[ch_name] = radio_controller.add_object(src, radiochannels[ch_name], RADIO_CHAT) + if(bluespace_radio) + if(bs_tx_preload_id) + //Try to find a receiver + for(var/obj/machinery/telecomms/receiver/RX in telecomms_list) + if(RX.id == bs_tx_preload_id) //Again, bs_tx is the thing to TRANSMIT TO, so a receiver. + bs_tx_weakref = weakref(RX) + RX.link_radio(src) + break + //Hmm, howabout an AIO machine + if(!bs_tx_weakref) + for(var/obj/machinery/telecomms/allinone/AIO in telecomms_list) + if(AIO.id == bs_tx_preload_id) + bs_tx_weakref = weakref(AIO) + AIO.link_radio(src) + break + if(!bs_tx_weakref) + testing("A radio [src] at [x],[y],[z] specified bluespace prelink IDs, but the machines with corresponding IDs ([bs_tx_preload_id], [bs_rx_preload_id]) couldn't be found.") + + if(bs_rx_preload_id) + var/found = 0 + //Try to find a transmitter + for(var/obj/machinery/telecomms/broadcaster/TX in telecomms_list) + if(TX.id == bs_rx_preload_id) //Again, bs_rx is the thing to RECEIVE FROM, so a transmitter. + TX.link_radio(src) + found = 1 + break + //Hmm, howabout an AIO machine + if(!found) + for(var/obj/machinery/telecomms/allinone/AIO in telecomms_list) + if(AIO.id == bs_rx_preload_id) + AIO.link_radio(src) + found = 1 + break + if(!found) + testing("A radio [src] at [x],[y],[z] specified bluespace prelink IDs, but the machines with corresponding IDs ([bs_tx_preload_id], [bs_rx_preload_id]) couldn't be found.") + + /obj/item/device/radio/attack_self(mob/user as mob) user.set_machine(src) interact(user) @@ -240,11 +284,10 @@ var/global/list/default_medbay_channels = list( if(.) SSnanoui.update_uis(src) -/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel) //BS12 EDIT +/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel, var/list/zlevels) //BS12 EDIT var/datum/radio_frequency/connection = null if(channel && channels && channels.len > 0) if (channel == "department") - //to_world("DEBUG: channel=\"[channel]\" switching to \"[channels[1]]\"") channel = channels[1] connection = secure_radio_connections[channel] else @@ -253,12 +296,15 @@ var/global/list/default_medbay_channels = list( if (!istype(connection)) return + if(!LAZYLEN(zlevels)) + zlevels = list(0) + var/static/mob/living/silicon/ai/announcer/A = new /mob/living/silicon/ai/announcer(src, null, null, 1) A.SetName(from) Broadcast_Message(connection, A, 0, "*garbled automated announcement*", src, message, from, "Automated Announcement", from, "synthesized voice", - 4, 0, list(0), connection.frequency, "states") + 4, 0, zlevels, connection.frequency, "states") // Interprets the message mode when talking into a radio, possibly returning a connection datum /obj/item/device/radio/proc/handle_message_mode(mob/living/M as mob, message, message_mode) @@ -310,7 +356,7 @@ var/global/list/default_medbay_channels = list( if (!istype(connection)) return FALSE - var/turf/position = get_turf(src) + var/pos_z = get_z(src) //#### Tagging the signal with all appropriate identity values ####// @@ -359,10 +405,63 @@ var/global/list/default_medbay_channels = list( jobname = "Unknown" voicemask = 1 + // First, we want to generate a new radio signal + var/datum/signal/signal = new + // --- Finally, tag the actual signal with the appropriate values --- + signal.data = list( + // Identity-associated tags: + "mob" = M, // store a reference to the mob + "mobtype" = M.type, // the mob's type + "realname" = real_name, // the mob's real name + "name" = displayname, // the mob's display name + "job" = jobname, // the mob's job + "key" = mobkey, // the mob's key + "vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood + "vname" = M.voice_name, // the name to display if the voice wasn't understood + "vmask" = voicemask, // 1 if the mob is using a voice gas mask - /* ###### Radio headsets can only broadcast through subspace ###### */ - if(subspace_transmission) + // We store things that would otherwise be kept in the actual mob + // so that they can be logged even AFTER the mob is deleted or something + + // Other tags: + "compression" = rand(45,50), // compressed radio signal + "message" = message, // the actual sent message + "connection" = connection, // the radio connection to use + "radio" = src, // stores the radio used for transmission + "slow" = 0, // how much to sleep() before broadcasting - simulates net lag + "traffic" = 0, // dictates the total traffic sum that the signal went through + "type" = SIGNAL_NORMAL, // determines what type of radio input it is: normal broadcast + "server" = null, // the last server to log this signal + "reject" = 0, // if nonzero, the signal will not be accepted by any broadcasting machinery + "level" = pos_z, // The source's z level + "language" = speaking, + "verb" = verb + ) + signal.frequency = connection.frequency // Quick frequency set + + var/filter_type = DATA_LOCAL //If we end up having to send it the old fashioned way, it's with this data var. + + /* ###### Bluespace radios talk directly to receivers (and only directly to receivers) ###### */ + if(bluespace_radio) + //Nothing to transmit to + if(!bs_tx_weakref) + to_chat(loc, "\The [src] buzzes to inform you of the lack of a functioning connection.") + return FALSE + + var/obj/machinery/telecomms/tx_to = bs_tx_weakref.resolve() + //Was linked, now destroyed or something + if(!tx_to) + bs_tx_weakref = null + to_chat(loc, "\The [src] buzzes to inform you of the lack of a functioning connection.") + return FALSE + + //Transmitted in the blind. If we get a message back, cool. If not, oh well. + signal.transmission_method = TRANSMISSION_BLUESPACE + return tx_to.receive_signal(signal) + + /* ###### Radios with subspace_transmission can only broadcast through subspace (unless they have adhoc_fallback) ###### */ + else if(subspace_transmission) var/list/jamming = is_jammed(src) if(jamming) var/distance = jamming["distance"] @@ -370,43 +469,9 @@ var/global/list/default_medbay_channels = list( return FALSE // First, we want to generate a new radio signal - var/datum/signal/signal = new - signal.transmission_method = 2 // 2 would be a subspace transmission. - // transmission_method could probably be enumerated through #define. Would be neater. + signal.transmission_method = TRANSMISSION_SUBSPACE - // --- Finally, tag the actual signal with the appropriate values --- - signal.data = list( - // Identity-associated tags: - "mob" = M, // store a reference to the mob - "mobtype" = M.type, // the mob's type - "realname" = real_name, // the mob's real name - "name" = displayname, // the mob's display name - "job" = jobname, // the mob's job - "key" = mobkey, // the mob's key - "vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood - "vname" = M.voice_name, // the name to display if the voice wasn't understood - "vmask" = voicemask, // 1 if the mob is using a voice gas mask - - // We store things that would otherwise be kept in the actual mob - // so that they can be logged even AFTER the mob is deleted or something - - // Other tags: - "compression" = rand(45,50), // compressed radio signal - "message" = message, // the actual sent message - "connection" = connection, // the radio connection to use - "radio" = src, // stores the radio used for transmission - "slow" = 0, // how much to sleep() before broadcasting - simulates net lag - "traffic" = 0, // dictates the total traffic sum that the signal went through - "type" = 0, // determines what type of radio input it is: normal broadcast - "server" = null, // the last server to log this signal - "reject" = 0, // if nonzero, the signal will not be accepted by any broadcasting machinery - "level" = position.z, // The source's z level - "language" = speaking, - "verb" = verb - ) - signal.frequency = connection.frequency // Quick frequency set - - //#### Sending the signal to all subspace receivers ####// + //#### Sending the signal to all subspace receivers ####// for(var/obj/machinery/telecomms/receiver/R in telecomms_list) R.receive_signal(signal) @@ -416,84 +481,47 @@ var/global/list/default_medbay_channels = list( R.receive_signal(signal) // Receiving code can be located in Telecommunications.dm - if(signal.data["done"] && position.z in signal.data["level"]) + if(signal.data["done"] && (pos_z in signal.data["level"])) return TRUE //Huzzah, sent via subspace else if(adhoc_fallback) //Less huzzah, we have to fallback to_chat(loc, "\The [src] pings as it falls back to local radio transmission.") subspace_transmission = FALSE - return Broadcast_Message(connection, M, voicemask, pick(M.speak_emote), - src, message, displayname, jobname, real_name, M.voice_name, - signal.transmission_method, signal.data["compression"], GetConnectedZlevels(position.z), connection.frequency,verb,speaking) - /* ###### Intercoms and station-bounced radios ###### */ + else //Oh well + return FALSE - var/filter_type = 2 + /* ###### Intercoms and station-bounced radios ###### */ + else + /* --- Intercoms can only broadcast to other intercoms, but bounced radios can broadcast to bounced radios and intercoms --- */ + if(istype(src, /obj/item/device/radio/intercom)) + filter_type = DATA_INTERCOM - /* --- Intercoms can only broadcast to other intercoms, but bounced radios can broadcast to bounced radios and intercoms --- */ - if(istype(src, /obj/item/device/radio/intercom)) - filter_type = 1 + /* --- Try to send a normal subspace broadcast first */ + signal.transmission_method = TRANSMISSION_SUBSPACE + signal.data["compression"] = 0 + for(var/obj/machinery/telecomms/receiver/R in telecomms_list) + R.receive_signal(signal) - var/datum/signal/signal = new - signal.transmission_method = 2 - - - /* --- Try to send a normal subspace broadcast first */ - - signal.data = list( - - "mob" = M, // store a reference to the mob - "mobtype" = M.type, // the mob's type - "realname" = real_name, // the mob's real name - "name" = displayname, // the mob's display name - "job" = jobname, // the mob's job - "key" = mobkey, // the mob's key - "vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood - "vname" = M.voice_name, // the name to display if the voice wasn't understood - "vmask" = voicemask, // 1 if the mob is using a voice gas mas - - "compression" = 0, // uncompressed radio signal - "message" = message, // the actual sent message - "connection" = connection, // the radio connection to use - "radio" = src, // stores the radio used for transmission - "slow" = 0, - "traffic" = 0, - "type" = 0, - "server" = null, - "reject" = 0, - "level" = position.z, - "language" = speaking, - "verb" = verb - ) - signal.frequency = connection.frequency // Quick frequency set + // Allinone can act as receivers. + for(var/obj/machinery/telecomms/allinone/R in telecomms_list) + R.receive_signal(signal) for(var/obj/machinery/telecomms/receiver/R in telecomms_list) R.receive_signal(signal) - if(signal.data["done"] && position.z in signal.data["level"]) - if(adhoc_fallback) - to_chat(loc, "\The [src] pings as it reestablishes subspace communications.") - subspace_transmission = TRUE - // we're done here. - return TRUE - - // Oh my god; the comms are down or something because the signal hasn't been broadcasted yet in our level. - // Send a mundane broadcast with limited targets: - - //THIS IS TEMPORARY. YEAH RIGHT - if(!connection) return FALSE //~Carn - -//VOREStation Add Start - if(bluespace_radio) - return Broadcast_Message(connection, M, voicemask, pick(M.speak_emote), - src, message, displayname, jobname, real_name, M.voice_name, - 0, signal.data["compression"], list(0), connection.frequency,verb,speaking) -//VOREStation Add End + if(signal.data["done"] && pos_z in signal.data["level"]) + if(adhoc_fallback) + to_chat(loc, "\The [src] pings as it reestablishes subspace communications.") + subspace_transmission = TRUE + // we're done here. + return TRUE + //Nothing handled any sort of remote radio-ing and returned before now, just squawk on this zlevel. return Broadcast_Message(connection, M, voicemask, pick(M.speak_emote), - src, message, displayname, jobname, real_name, M.voice_name, - filter_type, signal.data["compression"], GetConnectedZlevels(position.z), connection.frequency,verb,speaking) + src, message, displayname, jobname, real_name, M.voice_name, + filter_type, signal.data["compression"], using_map.get_map_levels(pos_z), connection.frequency, verb, speaking) /obj/item/device/radio/hear_talk(mob/M as mob, msg, var/verb = "says", var/datum/language/speaking = null) @@ -502,33 +530,20 @@ var/global/list/default_medbay_channels = list( talk_into(M, msg,null,verb,speaking) -/* -/obj/item/device/radio/proc/accept_rad(obj/item/device/radio/R as obj, message) - - if ((R.frequency == frequency && message)) - return TRUE - else if - - else - return null - return -*/ - /obj/item/device/radio/proc/receive_range(freq, level) // check if this radio can receive on the given frequency, and if so, // what the range is in which mobs will hear the radio // returns: -1 if can't receive, range otherwise - - if (wires.IsIndexCut(WIRE_RECEIVE)) + if(wires.IsIndexCut(WIRE_RECEIVE)) return -1 if(!listening) return -1 if(is_jammed(src)) return -1 if(!(0 in level)) - var/turf/position = get_turf(src) - if((!position || !(position.z in level)) && !bluespace_radio) //VOREStation Edit + var/pos_z = get_z(src) + if(!(pos_z in level)) return -1 if(freq in ANTAG_FREQS) if(!(src.syndie))//Checks to see if it's allowed on that frequency, based on the encryption keys diff --git a/code/game/objects/items/devices/radio/radiopack.dm b/code/game/objects/items/devices/radio/radiopack.dm new file mode 100644 index 0000000000..c2ba25ecc2 --- /dev/null +++ b/code/game/objects/items/devices/radio/radiopack.dm @@ -0,0 +1,153 @@ +/obj/item/device/bluespaceradio + name = "bluespace radio" + desc = "A powerful radio that uses a tiny bluespace wormhole to send signals directly to subspace receivers and transmitters, bypassing the limitations of subspace." + icon = 'icons/obj/radio.dmi' + icon_state = "radiopack" + item_state = "radiopack" + slot_flags = SLOT_BACK + force = 5 + throwforce = 6 + preserve_item = 1 + w_class = ITEMSIZE_LARGE + action_button_name = "Remove/Replace Handset" + + var/obj/item/device/radio/bluespacehandset/linked/handset = /obj/item/device/radio/bluespacehandset/linked + +/obj/item/device/bluespaceradio/Initialize() + . = ..() + if(ispath(handset)) + handset = new handset(src, src) + +/obj/item/device/bluespaceradio/Destroy() + . = ..() + QDEL_NULL(handset) + +/obj/item/device/bluespaceradio/ui_action_click() + toggle_handset() + +/obj/item/device/bluespaceradio/attack_hand(var/mob/user) + if(loc == user) + toggle_handset() + else + ..() + +/obj/item/device/bluespaceradio/MouseDrop() + if(ismob(loc)) + if(!CanMouseDrop(src)) + return + var/mob/M = loc + if(!M.unEquip(src)) + return + add_fingerprint(usr) + M.put_in_any_hand_if_possible(src) + +/obj/item/device/bluespaceradio/attackby(var/obj/item/weapon/W, var/mob/user, var/params) + if(W == handset) + reattach_handset(user) + else + return ..() + +/obj/item/device/bluespaceradio/verb/toggle_handset() + set name = "Toggle Handset" + set category = "Object" + + var/mob/living/carbon/human/user = usr + if(!handset) + to_chat(user, "The handset is missing!") + return + + if(handset.loc != src) + reattach_handset(user) //Remove from their hands and back onto the defib unit + return + + if(!slot_check()) + to_chat(user, "You need to equip [src] before taking out [handset].") + else + if(!usr.put_in_hands(handset)) //Detach the handset into the user's hands + to_chat(user, "You need a free hand to hold the handset!") + update_icon() //success + +//checks that the base unit is in the correct slot to be used +/obj/item/device/bluespaceradio/proc/slot_check() + var/mob/M = loc + if(!istype(M)) + return 0 //not equipped + + if((slot_flags & SLOT_BACK) && M.get_equipped_item(slot_back) == src) + return 1 + if((slot_flags & SLOT_BACK) && M.get_equipped_item(slot_s_store) == src) + return 1 + + return 0 + +/obj/item/device/bluespaceradio/dropped(var/mob/user) + ..() + reattach_handset(user) //handset attached to a base unit should never exist outside of their base unit or the mob equipping the base unit + +/obj/item/device/bluespaceradio/proc/reattach_handset(var/mob/user) + if(!handset) return + + if(ismob(handset.loc)) + var/mob/M = handset.loc + if(M.drop_from_inventory(handset, src)) + to_chat(user, "\The [handset] snaps back into the main unit.") + else + handset.forceMove(src) + +//Subspace Radio Handset +/obj/item/device/radio/bluespacehandset + name = "bluespace radio handset" + desc = "A large walkie talkie attached to the bluespace radio by a retractable cord. It sits comfortably on a slot in the radio when not in use." + bluespace_radio = TRUE + icon_state = "signaller" + slot_flags = null + w_class = ITEMSIZE_LARGE + canhear_range = 1 + +/obj/item/device/radio/bluespacehandset/linked + var/obj/item/device/bluespaceradio/base_unit + +/obj/item/device/radio/bluespacehandset/linked/Initialize(mapload, var/obj/item/device/bluespaceradio/radio) + base_unit = radio + . = ..() + +/obj/item/device/radio/bluespacehandset/linked/Destroy() + if(base_unit) + //ensure the base unit's icon updates + if(base_unit.handset == src) + base_unit.handset = null + base_unit = null + return ..() + +/obj/item/device/radio/bluespacehandset/linked/dropped(var/mob/user) + ..() //update twohanding + if(base_unit) + base_unit.reattach_handset(user) //handset attached to a base unit should never exist outside of their base unit or the mob equipping the base unit + +/obj/item/device/radio/bluespacehandset/linked/receive_range(var/freq, var/list/level) + //Only care about megabroadcasts or things that are targeted at us + if(!(0 in level)) + return -1 + if(wires.IsIndexCut(WIRE_RECEIVE)) + return -1 + if(!listening) + return -1 + if(is_jammed(src)) + return -1 + if (!on) + return -1 + if (!freq) //recieved on main frequency + if (!listening) + return -1 + else + var/accept = (freq==frequency && listening) + if (!accept) + for (var/ch_name in channels) + var/datum/radio_frequency/RF = secure_radio_connections[ch_name] + if (RF && RF.frequency==freq && (channels[ch_name]&FREQ_LISTENING)) + accept = 1 + break + if (!accept) + return -1 + + return canhear_range diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 73a8e7bc5b..ace7d48e91 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -525,7 +525,7 @@ Traitors and the like can also be revived with the previous role mostly intact. //If we're announcing their arrival if(announce) - AnnounceArrival(new_character, new_character.mind.assigned_role) + AnnounceArrival(new_character, new_character.mind.assigned_role, "Common", new_character.z) log_admin("[admin] has spawned [player_key]'s character [new_character.real_name].") message_admins("[admin] has spawned [player_key]'s character [new_character.real_name].", 1) diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 209516ec88..799e177304 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -419,18 +419,19 @@ //Grab some data from the character prefs for use in random news procs. - AnnounceArrival(character, rank, join_message) + AnnounceArrival(character, rank, join_message, announce_channel, character.z) else - AnnounceCyborg(character, rank, join_message) + AnnounceCyborg(character, rank, join_message, announce_channel, character.z) qdel(src) -/mob/new_player/proc/AnnounceCyborg(var/mob/living/character, var/rank, var/join_message) +/mob/new_player/proc/AnnounceCyborg(var/mob/living/character, var/rank, var/join_message, var/channel, var/zlevel) if (ticker.current_state == GAME_STATE_PLAYING) + var/list/zlevels = zlevel ? using_map.get_map_levels(zlevel, TRUE) : null if(character.mind.role_alt_title) rank = character.mind.role_alt_title // can't use their name here, since cyborg namepicking is done post-spawn, so we'll just say "A new Cyborg has arrived"/"A new Android has arrived"/etc. - global_announcer.autosay("A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer") + global_announcer.autosay("A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer", channel, zlevels) /mob/new_player/proc/LateChoices() var/name = client.prefs.be_random_name ? "friend" : client.prefs.real_name diff --git a/code/modules/modular_computers/hardware/network_card.dm b/code/modules/modular_computers/hardware/network_card.dm index 69f4a8bb64..2f382e0f4d 100644 --- a/code/modules/modular_computers/hardware/network_card.dm +++ b/code/modules/modular_computers/hardware/network_card.dm @@ -79,20 +79,25 @@ var/global/ntnet_card_uid = 1 return 0 if(holder2) - var/turf/T = get_turf(holder2) - if(!istype(T)) //no reception in nullspace + var/holderz = get_z(holder2) + if(!holderz) //no reception in nullspace return 0 - if(T.z in using_map.station_levels) - // Computer is on station. Low/High signal depending on what type of network card you have - if(long_range) - return 2 - else - return 1 - if(T.z in using_map.contact_levels) //not on station, but close enough for radio signal to travel - if(long_range) // Computer is not on station, but it has upgraded network card. Low signal. - return 1 - - return 0 // Computer is not on station and does not have upgraded network card. No signal. + var/list/zlevels_in_range = using_map.get_map_levels(holderz, long_range) + var/best = 0 + for(var/relay in ntnet_global.relays) + var/obj/machinery/ntnet_relay/R = relay + //Relay is down + if(!R.operable()) + continue + //We're on the same z + if(R.z == holderz) + best = 2 + break // No point in going further + //Not on the same z but within range anyway + if(R.z in zlevels_in_range) + best = 1 + return best + return 0 // No computer! /obj/item/weapon/computer_hardware/network_card/Destroy() if(holder2 && (holder2.network_card == src)) diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi index f3e7e10b85..63958e93a4 100644 Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ diff --git a/icons/obj/radio.dmi b/icons/obj/radio.dmi index 98871c1a02..c565483599 100644 Binary files a/icons/obj/radio.dmi and b/icons/obj/radio.dmi differ diff --git a/maps/~map_system/maps.dm b/maps/~map_system/maps.dm index 524482d83f..a7a44f7356 100644 --- a/maps/~map_system/maps.dm +++ b/maps/~map_system/maps.dm @@ -159,20 +159,44 @@ var/list/all_maps = list() empty_levels = list(world.maxz) return pick(empty_levels) -// Get the list of zlevels that a computer on srcz can see maps of (for power/crew monitor, cameras, etc) -// The long_range parameter expands the coverage. Default is to return map_levels for long range otherwise just srcz. -// zLevels outside station_levels will return an empty list. -/datum/map/proc/get_map_levels(var/srcz, var/long_range = TRUE) - if (long_range && (srcz in map_levels)) - return map_levels - else if (srcz in station_levels) - return list(srcz) +// Get a list of 'nearby' or 'connected' zlevels. +// You should at least return a list with the given z if nothing else. +/datum/map/proc/get_map_levels(var/srcz, var/long_range = FALSE, var/om_range = -1) + //Overmap behavior + if(use_overmap) + //Get what sector we're in + var/obj/effect/overmap/visitable/O = get_overmap_sector(srcz) + if(!istype(O)) + //Not in a sector, just the passed zlevel + return list(srcz) + + //Just the sector we're in + if(om_range == -1) + return O.map_z.Copy() + + //Otherwise every sector we're on top of + var/list/connections = list() + var/turf/T = get_turf(O) + var/turfrange = long_range ? max(0, om_range) : om_range + for(var/obj/effect/overmap/visitable/V in range(turfrange, T)) + connections += V.map_z // Adding list to list adds contents + return connections + + //Traditional behavior else - return list() + //If long range, and they're at least in contact levels, return contact levels. + if (long_range && (srcz in contact_levels)) + return contact_levels.Copy() + //If in station levels, return station levels + else if (srcz in station_levels) + return station_levels.Copy() + //Just give them back their zlevel + else + return list(srcz) /datum/map/proc/get_zlevel_name(var/index) var/datum/map_z_level/Z = zlevels["[index]"] - return Z.name + return Z?.name // Access check is of the type requires one. These have been carefully selected to avoid allowing the janitor to see channels he shouldn't // This list needs to be purged but people insist on adding more cruft to the radio. diff --git a/vorestation.dme b/vorestation.dme index 71ff78008b..248ecf5688 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -1128,6 +1128,7 @@ #include "code\game\objects\items\devices\radio\jammer_vr.dm" #include "code\game\objects\items\devices\radio\radio.dm" #include "code\game\objects\items\devices\radio\radio_vr.dm" +#include "code\game\objects\items\devices\radio\radiopack.dm" #include "code\game\objects\items\robot\robot_items.dm" #include "code\game\objects\items\robot\robot_parts.dm" #include "code\game\objects\items\robot\robot_upgrades.dm"