diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm
index 5178f935942..684b439d48e 100644
--- a/code/__DEFINES/dcs/signals/signals_object.dm
+++ b/code/__DEFINES/dcs/signals/signals_object.dm
@@ -265,6 +265,8 @@
///called from base of /obj/item/radio/proc/set_frequency(): (list/args)
#define COMSIG_RADIO_NEW_FREQUENCY "radio_new_frequency"
+///called from base of /obj/item/radio/proc/talk_into(): (atom/movable/M, message, channel)
+#define COMSIG_RADIO_NEW_MESSAGE "radio_new_message"
// /obj/item/pen signals
diff --git a/code/__DEFINES/radio.dm b/code/__DEFINES/radio.dm
index d236b91551f..a9a63dc35bf 100644
--- a/code/__DEFINES/radio.dm
+++ b/code/__DEFINES/radio.dm
@@ -46,6 +46,10 @@
#define RADIO_KEY_CENTCOM "y"
#define RADIO_TOKEN_CENTCOM ":y"
+#define RADIO_CHANNEL_UPLINK "Uplink"
+#define RADIO_KEY_UPLINK "d"
+#define RADIO_TOKEN_UPLINK ":d"
+
#define RADIO_CHANNEL_CTF_RED "Red Team"
#define RADIO_CHANNEL_CTF_BLUE "Blue Team"
#define RADIO_CHANNEL_CTF_GREEN "Green Team"
@@ -55,6 +59,7 @@
#define MIN_FREE_FREQ 1201 // -------------------------------------------------
// Frequencies are always odd numbers and range from 1201 to 1599.
+#define FREQ_UPLINK 1211 // Dummy loopback frequency, used for radio uplink. Not seen in game.
#define FREQ_SYNDICATE 1213 // Nuke op comms frequency, dark brown
#define FREQ_CTF_RED 1215 // CTF red team comms frequency, red
#define FREQ_CTF_BLUE 1217 // CTF blue team comms frequency, blue
diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm
index 2659150cd4e..81fa46b39f9 100644
--- a/code/datums/components/uplink.dm
+++ b/code/datums/components/uplink.dm
@@ -62,7 +62,7 @@
RegisterSignal(parent, COMSIG_TABLET_CHANGE_ID, PROC_REF(new_ringtone))
RegisterSignal(parent, COMSIG_TABLET_CHECK_DETONATE, PROC_REF(check_detonate))
else if(istype(parent, /obj/item/radio))
- RegisterSignal(parent, COMSIG_RADIO_NEW_FREQUENCY, PROC_REF(new_frequency))
+ RegisterSignal(parent, COMSIG_RADIO_NEW_MESSAGE, PROC_REF(new_message))
else if(istype(parent, /obj/item/pen))
RegisterSignal(parent, COMSIG_PEN_ROTATED, PROC_REF(pen_rotation))
@@ -359,6 +359,21 @@
if(ismob(master.loc))
interact(null, master.loc)
+/datum/component/uplink/proc/new_message(datum/source, user, message, channel)
+ SIGNAL_HANDLER
+
+ if(channel != RADIO_CHANNEL_UPLINK)
+ return
+
+ if(!findtext(lowertext(message), lowertext(unlock_code)))
+ if(failsafe_code && findtext(lowertext(message), lowertext(failsafe_code)))
+ failsafe() // no point returning cannot radio, youre probably ded
+ return
+ locked = FALSE
+ interact(null, user)
+ to_chat(user, "As you whisper the code into your headset, a soft chime fills your ears.")
+ return COMPONENT_CANNOT_USE_RADIO
+
// Pen signal responses
/datum/component/uplink/proc/pen_rotation(datum/source, degrees, mob/living/carbon/user)
@@ -385,7 +400,7 @@
if(istype(parent,/obj/item/modular_computer/tablet))
unlock_note = "Uplink Passcode: [unlock_code] ([P.name])."
else if(istype(parent,/obj/item/radio))
- unlock_note = "Radio Frequency: [format_frequency(unlock_code)] ([P.name])."
+ unlock_note = "Radio Passcode: [unlock_code] ([P.name], :d channel)."
else if(istype(parent,/obj/item/pen))
unlock_note = "Uplink Degrees: [english_list(unlock_code)] ([P.name])."
@@ -393,7 +408,7 @@
if(istype(parent,/obj/item/modular_computer/tablet))
return "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]"
else if(istype(parent,/obj/item/radio))
- return return_unused_frequency()
+ return pick(GLOB.phonetic_alphabet)
else if(istype(parent,/obj/item/pen))
var/list/L = list()
for(var/i in 1 to PEN_ROTATIONS)
diff --git a/code/datums/mind/antag.dm b/code/datums/mind/antag.dm
index e915365edea..3fe7ec1d2ad 100644
--- a/code/datums/mind/antag.dm
+++ b/code/datums/mind/antag.dm
@@ -126,6 +126,11 @@
var/implant = FALSE
var/uplink_spawn_location = traitor_mob.client?.prefs?.read_preference(/datum/preference/choiced/uplink_location)
+ var/cant_speak = (HAS_TRAIT(traitor_mob, TRAIT_MUTE) || traitor_mob.mind?.assigned_role.title == JOB_MIME)
+ if(uplink_spawn_location == UPLINK_RADIO && cant_speak)
+ if(!silent)
+ to_chat(traitor_mob, span_warning("You have been deemed ineligible for a radio uplink. Supplying standard uplink instead."))
+ uplink_spawn_location = UPLINK_PDA
switch (uplink_spawn_location)
if(UPLINK_PDA)
uplink_loc = PDA
@@ -164,7 +169,7 @@
new_uplink.uplink_handler.assigned_role = traitor_mob.mind.assigned_role.title
new_uplink.uplink_handler.assigned_species = traitor_mob.dna.species.id
if(uplink_loc == R)
- unlock_text = "Your Uplink is cunningly disguised as your [R.name]. Simply dial the frequency [format_frequency(new_uplink.unlock_code)] to unlock its hidden features."
+ unlock_text = "Your Uplink is cunningly disguised as your [R.name]. Simply speak \"[new_uplink.unlock_code]\" into frequency :d to unlock its hidden features."
else if(uplink_loc == PDA)
unlock_text = "Your Uplink is cunningly disguised as your [PDA.name]. Simply enter the code \"[new_uplink.unlock_code]\" into the ring tone selection to unlock its hidden features."
else if(uplink_loc == P)
diff --git a/code/game/communications.dm b/code/game/communications.dm
index ba8c29ed250..d8e12a646d3 100644
--- a/code/game/communications.dm
+++ b/code/game/communications.dm
@@ -100,6 +100,7 @@ GLOBAL_LIST_INIT(radiochannels, list(
RADIO_CHANNEL_SECURITY = FREQ_SECURITY,
RADIO_CHANNEL_CENTCOM = FREQ_CENTCOM,
RADIO_CHANNEL_SYNDICATE = FREQ_SYNDICATE,
+ RADIO_CHANNEL_UPLINK = FREQ_UPLINK,
RADIO_CHANNEL_SUPPLY = FREQ_SUPPLY,
RADIO_CHANNEL_SERVICE = FREQ_SERVICE,
RADIO_CHANNEL_AI_PRIVATE = FREQ_AI_PRIVATE,
@@ -118,6 +119,7 @@ GLOBAL_LIST_INIT(reverseradiochannels, list(
"[FREQ_SECURITY]" = RADIO_CHANNEL_SECURITY,
"[FREQ_CENTCOM]" = RADIO_CHANNEL_CENTCOM,
"[FREQ_SYNDICATE]" = RADIO_CHANNEL_SYNDICATE,
+ "[FREQ_UPLINK]" = RADIO_CHANNEL_UPLINK,
"[FREQ_SUPPLY]" = RADIO_CHANNEL_SUPPLY,
"[FREQ_SERVICE]" = RADIO_CHANNEL_SERVICE,
"[FREQ_AI_PRIVATE]" = RADIO_CHANNEL_AI_PRIVATE,
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 2c356216d43..42ff5532431 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -224,6 +224,8 @@
/obj/item/radio/talk_into(atom/movable/talking_movable, message, channel, list/spans, datum/language/language, list/message_mods)
if(SEND_SIGNAL(talking_movable, COMSIG_MOVABLE_USING_RADIO, src) & COMPONENT_CANNOT_USE_RADIO)
return
+ if(SEND_SIGNAL(src, COMSIG_RADIO_NEW_MESSAGE, talking_movable, message, channel) & COMPONENT_CANNOT_USE_RADIO)
+ return
if(!spans)
spans = list(talking_movable.speech_span)
diff --git a/code/game/say.dm b/code/game/say.dm
index d438abc6894..487c255bde1 100644
--- a/code/game/say.dm
+++ b/code/game/say.dm
@@ -13,6 +13,7 @@ GLOBAL_LIST_INIT(freqtospan, list(
"[FREQ_COMMAND]" = "comradio",
"[FREQ_AI_PRIVATE]" = "aiprivradio",
"[FREQ_SYNDICATE]" = "syndradio",
+ "[FREQ_UPLINK]" = "syndradio", // this probably shouldnt appear ingame
"[FREQ_CENTCOM]" = "centcomradio",
"[FREQ_CTF_RED]" = "redteamradio",
"[FREQ_CTF_BLUE]" = "blueteamradio",
diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm
index 964eb38875d..a4a3e0787bb 100644
--- a/code/modules/mob/living/living_say.dm
+++ b/code/modules/mob/living/living_say.dm
@@ -18,6 +18,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
// Faction
RADIO_KEY_SYNDICATE = RADIO_CHANNEL_SYNDICATE,
+ RADIO_KEY_UPLINK = RADIO_CHANNEL_UPLINK,
RADIO_KEY_CENTCOM = RADIO_CHANNEL_CENTCOM,
// Admin