diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm
index b55a354945..cd65fb9f91 100644
--- a/code/game/machinery/telecomms/broadcaster.dm
+++ b/code/game/machinery/telecomms/broadcaster.dm
@@ -250,7 +250,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(istype(R, /obj/item/device/radio/headset))
+ if(istype(R, /obj/item/device/radio/headset) && !R.adhoc_fallback)
continue
if(R.receive_range(display_freq, level) > -1)
diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm
index 94aef886d0..38cac0737e 100644
--- a/code/game/machinery/telecomms/telecomunications.dm
+++ b/code/game/machinery/telecomms/telecomunications.dm
@@ -314,7 +314,25 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
circuitboard = "/obj/item/weapon/circuitboard/telecomms/hub"
long_range_link = 1
netspeed = 40
+ var/list/telecomms_map
+/obj/machinery/telecomms/hub/initialize()
+ . = ..()
+ LAZYINITLIST(telecomms_map)
+
+/obj/machinery/telecomms/hub/process()
+ . = ..()
+ telecomms_map.Cut()
+
+ if(!on)
+ return
+
+ for(var/M in links)
+ if(istype(M,/obj/machinery/telecomms/receiver) || istype(M,/obj/machinery/telecomms/relay))
+ var/obj/machinery/telecomms/R = M
+ if(!R.on)
+ continue
+ telecomms_map |= R.listening_level
/obj/machinery/telecomms/hub/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from)
if(is_freq_listening(signal))
@@ -645,9 +663,40 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list()
var/garbage_collector = 1 // if set to 0, will not be garbage collected
var/input_type = "Speech File"
+//Generic telecomm connectivity test proc
+/proc/can_telecomm(var/atom/A, var/atom/B, var/ad_hoc = FALSE)
+ if(!A || !B)
+ log_debug("can_telecomm(): Undefined endpoints!")
+ return FALSE
+ //Can't in this case, obviously!
+ if(is_jammed(A) || is_jammed(B))
+ return FALSE
+ //Items don't have a Z when inside an object or mob
+ var/turf/src_turf = get_turf(A)
+ var/turf/dst_turf = get_turf(B)
+ //Nullspace, probably.
+ if(!src_turf || !dst_turf)
+ return FALSE
+ var/src_z = src_turf.z
+ var/dst_z = dst_turf.z
+ //Mysterious!
+ if(!src_z || !dst_z)
+ return FALSE
+ //We can do the simple check first, if you have ad_hoc radios.
+ if(ad_hoc && src_z == dst_z)
+ return TRUE
+
+ //Let's look at hubs and see what we got.
+ var/can_comm = FALSE
+ for(var/obj/machinery/telecomms/hub/H in telecomms_list)
+ if((src_z in H.telecomms_map) && (dst_z in H.telecomms_map))
+ can_comm = TRUE
+ break
+
+ return can_comm
diff --git a/code/game/objects/items/devices/communicator/communicator.dm b/code/game/objects/items/devices/communicator/communicator.dm
index 4ab3644374..cac80c84d0 100644
--- a/code/game/objects/items/devices/communicator/communicator.dm
+++ b/code/game/objects/items/devices/communicator/communicator.dm
@@ -173,13 +173,8 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
// Parameters: None
// Description: Simple check to see if the exonet node is active.
/obj/item/device/communicator/proc/get_connection_to_tcomms()
- if(node && node.on && node.allow_external_communicators && !is_jammed(src))
- // VOREStation Edit Start - Lose connection if too far from our exonet node.
- var/turf/T = get_turf(src)
- if(!T || !is_on_same_plane_or_station(T.z, node.z))
- return 0
- // VOREStation Edit End
- return 1
+ if(node && node.on && node.allow_external_communicators)
+ return can_telecomm(src,node)
return 0
// Proc: process()
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 75abb260f1..1bf6bb3f9c 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -39,6 +39,7 @@ var/global/list/default_medbay_channels = list(
var/listening = 1
var/list/channels = list() //see communications.dm for full list. First channel is a "default" for :h
var/subspace_transmission = 0
+ var/adhoc_fallback = FALSE //Falls back to 'radio' mode if subspace not available
var/syndie = 0//Holder to see if it's a syndicate encrypted radio
var/centComm = 0//Holder to see if it's a CentCom encrypted radio
flags = CONDUCT
@@ -414,9 +415,15 @@ var/global/list/default_medbay_channels = list(
for(var/obj/machinery/telecomms/allinone/R in telecomms_list)
R.receive_signal(signal)
- // Receiving code can be located in Telecommunications.dm
- return signal.data["done"] && position.z in signal.data["level"]
+ if(signal.data["done"] && position.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"], list(position.z), connection.frequency,verb,speaking)
/* ###### Intercoms and station-bounced radios ###### */
@@ -463,10 +470,10 @@ var/global/list/default_medbay_channels = list(
for(var/obj/machinery/telecomms/receiver/R in telecomms_list)
R.receive_signal(signal)
-
- sleep(rand(10,25)) // wait a little...
-
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 1
diff --git a/icons/obj/radio.dmi b/icons/obj/radio.dmi
index 86e39f0c58..98871c1a02 100644
Binary files a/icons/obj/radio.dmi and b/icons/obj/radio.dmi differ
diff --git a/icons/obj/radio_vr.dmi b/icons/obj/radio_vr.dmi
index 9c1d7cd007..4358e233b8 100644
Binary files a/icons/obj/radio_vr.dmi and b/icons/obj/radio_vr.dmi differ
diff --git a/maps/southern_cross/items/headset_sc.dm b/maps/southern_cross/items/headset_sc.dm
index 755fccaf10..d7212210f3 100644
--- a/maps/southern_cross/items/headset_sc.dm
+++ b/maps/southern_cross/items/headset_sc.dm
@@ -1,20 +1,38 @@
/obj/item/device/radio/headset/pilot
name = "pilot's headset"
- desc = "A bowman headset used by pilots, has access to supply and explorer channels."
- icon_state = "cargo_headset_alt"
+ desc = "A headset used by pilots, has access to supply and explorer channels."
+ icon_state = "pilot_headset"
item_state = "headset"
ks2type = /obj/item/device/encryptionkey/pilot
+ adhoc_fallback = TRUE //VOREStation Edit
+
+/obj/item/device/radio/headset/pilot/alt
+ name = "pilot's bowman headset"
+ desc = "A bowman headset used by pilots, has access to supply and explorer channels."
+ icon_state = "pilot_headset_alt"
/obj/item/device/radio/headset/explorer
name = "explorer's headset"
desc = "Headset used by explorers for exploring. Access to the explorer channel."
- icon_state = "mine_headset"
+ icon_state = "exp_headset"
item_state = "headset"
ks2type = /obj/item/device/encryptionkey/explorer
+ adhoc_fallback = TRUE //VOREStation Edit
-/obj/item/device/radio/headset/headset_sar
+/obj/item/device/radio/headset/explorer/alt
+ name = "explorer's bowman headset"
+ desc = "Bowman headset used by explorers for exploring. Access to the explorer channel."
+ icon_state = "exp_headset_alt"
+
+/obj/item/device/radio/headset/sar
name = "sar radio headset"
desc = "A headset for search and rescue."
- icon_state = "med_headset"
+ icon_state = "sar_headset"
item_state = "headset"
- ks2type = /obj/item/device/encryptionkey/sar
\ No newline at end of file
+ ks2type = /obj/item/device/encryptionkey/sar
+ adhoc_fallback = TRUE //VOREStation Edit
+
+/obj/item/device/radio/headset/sar/alt
+ name = "sar radio bowman headset"
+ desc = "A bowman headset for search and rescue."
+ icon_state = "sar_headset_alt"
diff --git a/maps/southern_cross/job/outfits.dm b/maps/southern_cross/job/outfits.dm
index 16717a71df..22cf52a403 100644
--- a/maps/southern_cross/job/outfits.dm
+++ b/maps/southern_cross/job/outfits.dm
@@ -36,7 +36,7 @@ Keep outfits simple. Spawn with basic uniforms and minimal gear. Gear instead go
suit = /obj/item/clothing/suit/storage/toggle/bomber/pilot
gloves = /obj/item/clothing/gloves/fingerless
glasses = /obj/item/clothing/glasses/fakesunglasses/aviator
- l_ear = /obj/item/device/radio/headset/pilot
+ l_ear = /obj/item/device/radio/headset/pilot/alt
id_slot = slot_wear_id
pda_slot = slot_belt
pda_type = /obj/item/device/pda/cargo // Brown looks more rugged
@@ -48,7 +48,7 @@ Keep outfits simple. Spawn with basic uniforms and minimal gear. Gear instead go
uniform = /obj/item/clothing/under/utility/blue
suit = /obj/item/clothing/suit/storage/hooded/wintercoat/medical/sar
shoes = /obj/item/clothing/shoes/boots/winter/explorer
- l_ear = /obj/item/device/radio/headset/headset_sar
+ l_ear = /obj/item/device/radio/headset/sar
l_hand = /obj/item/weapon/storage/firstaid/adv
belt = /obj/item/weapon/storage/belt/medical/emt
pda_slot = slot_l_store
diff --git a/maps/southern_cross/structures/closets/misc.dm b/maps/southern_cross/structures/closets/misc.dm
index 403ef49e86..934b0d8b3d 100644
--- a/maps/southern_cross/structures/closets/misc.dm
+++ b/maps/southern_cross/structures/closets/misc.dm
@@ -93,7 +93,7 @@
new /obj/item/clothing/mask/gas(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat/medical/sar(src)
new /obj/item/clothing/shoes/boots/winter/explorer(src)
- new /obj/item/device/radio/headset/headset_sar(src)
+ new /obj/item/device/radio/headset/sar(src)
new /obj/item/weapon/cartridge/medical(src)
new /obj/item/device/flashlight(src)
new /obj/item/weapon/tank/emergency/oxygen/engi(src)
@@ -130,7 +130,7 @@
new /obj/item/clothing/mask/gas/half(src)
new /obj/item/clothing/shoes/black(src)
new /obj/item/clothing/gloves/fingerless(src)
- new /obj/item/device/radio/headset/pilot(src)
+ new /obj/item/device/radio/headset/pilot/alt(src)
new /obj/item/device/flashlight(src)
new /obj/item/weapon/reagent_containers/food/snacks/liquidfood(src)
new /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle(src)