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"