Adds some intercom mapping templates (#95309)

## About The Pull Request

Adds some intercom templates based on some commonly mapped in var-edited
intercoms
- Interrogation
- AI private (AI upload)
- AI private (AI antechamber)
- AI private (AI chamber)
- Free range
- Free range (AI chamber)

Also adds some templates for the recently added
encryption-key-in-intercom mechanic
- Departmental intercoms

Doesn't map in any of these templates (yet) 

Also allows for radios to have locked keyslots in addition to locked
frequencies

## Why it's good for the game

Makes it a bit easier to map intercoms, particularly for event maps

## Changelog

🆑 Melbert
code: Radios can now have their keyslot locked, though no radios
currently have a keyslot lock. However, report any bugs with being
unable to emag, install, or remove radio keys.
/🆑
This commit is contained in:
MrMelbert
2026-03-13 15:19:59 -04:00
committed by GitHub
parent 9443d03cd3
commit 71e2fe4447
3 changed files with 189 additions and 28 deletions
+9
View File
@@ -96,6 +96,7 @@
#define FREQ_ENGINEERING 1357 // Engineering comms frequency, orange
#define FREQ_SECURITY 1359 // Security comms frequency, red
#define FREQ_ENTERTAINMENT 1415 // Used by entertainment monitors, cyan
#define FREQ_INTERROGATION 1423
#define FREQ_HOLOGRID_SOLUTION 1433
#define FREQ_STATUS_DISPLAYS 1435
@@ -113,6 +114,7 @@
#define FREQ_COMMON 1459 // Common comms frequency, dark green
#define MIN_UNUSED_FREQ 1461 // Prevents rolling AI Private or Common
#define FREQ_CONFESSIONAL 1481
#define MAX_FREQ 1489 // ------------------------------------------------------
@@ -153,6 +155,13 @@
/// Radio frequency is locked and unchangeable, but can be unlocked by an emag
#define RADIO_FREQENCY_EMAGGABLE_LOCK 2
/// Keyslot is unlocked and can be removed by anyone
#define RADIO_KEYSLOT_UNLOCKED 0
/// Keyslot is locked, unchangeable by players
#define RADIO_KEYSLOT_LOCKED 1
/// Keyslot is locked and unchangeable, but can be unlocked by an emag
#define RADIO_KEYSLOT_EMAGGABLE_LOCK 2
///Bitflag for if a headset can use the syndicate radio channel
#define RADIO_SPECIAL_SYNDIE (1<<0)
///Bitflag for if a headset can use the centcom radio channel
+169 -27
View File
@@ -58,11 +58,18 @@
. += span_notice("Speaking through this intercom will anonymize your voice.")
if(freqlock == RADIO_FREQENCY_UNLOCKED)
if(obj_flags & EMAGGED)
if((obj_flags & EMAGGED) && initial(freqlock) == RADIO_FREQENCY_EMAGGABLE_LOCK)
. += span_warning("Its frequency lock has been shorted...")
else
. += span_notice("It has a frequency lock set to [frequency/10].")
if(keylock == RADIO_KEYSLOT_UNLOCKED)
if((obj_flags & EMAGGED) && initial(keylock) == RADIO_KEYSLOT_EMAGGABLE_LOCK)
. += span_warning("Its keyslot's security screws have been uplifted...")
else
. += span_notice("The screws in its keyslot are [keylock == RADIO_KEYSLOT_LOCKED ? "stripped" : "fastened tight"], \
preventing the removal of its encryption key[keylock == RADIO_KEYSLOT_LOCKED ? "" : " without some kind of magnet"].")
/obj/item/radio/intercom/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
if(held_item?.tool_behaviour == TOOL_SCREWDRIVER)
@@ -164,26 +171,33 @@
. = ..()
if(obj_flags & EMAGGED)
return
return .
switch(freqlock)
// Emagging an intercom with an emaggable lock will remove the lock
if(RADIO_FREQENCY_EMAGGABLE_LOCK)
balloon_alert(user, "frequency lock cleared")
playsound(src, SFX_SPARKS, 75, TRUE, SILENCED_SOUND_EXTRARANGE)
freqlock = RADIO_FREQENCY_UNLOCKED
obj_flags |= EMAGGED
return TRUE
if(!freqlock && !keylock)
balloon_alert(user, "no locks to break!")
return .
// A fully locked one will do nothing, as locked is intended to be used for stuff that should never be changed
if(RADIO_FREQENCY_LOCKED)
balloon_alert(user, "can't override frequency lock!")
playsound(src, 'sound/machines/buzz/buzz-two.ogg', 50, FALSE, SILENCED_SOUND_EXTRARANGE)
return
var/message = ""
if(freqlock == RADIO_FREQENCY_EMAGGABLE_LOCK && keylock == RADIO_KEYSLOT_EMAGGABLE_LOCK)
message = "frequency and key lock"
else if(freqlock == RADIO_FREQENCY_EMAGGABLE_LOCK)
message = "frequency lock"
else if(keylock == RADIO_KEYSLOT_EMAGGABLE_LOCK)
message = "key lock"
// Emagging an unlocked one will do nothing, for now
else
return
if(!message)
balloon_alert(user, "can't break lock[(freqlock && keylock) ? "s" : ""]!")
playsound(src, 'sound/machines/buzz/buzz-two.ogg', 50, FALSE, SILENCED_SOUND_EXTRARANGE)
return .
balloon_alert(user, "[message] broken")
playsound(src, SFX_SPARKS, 75, TRUE, SILENCED_SOUND_EXTRARANGE)
if(freqlock == RADIO_FREQENCY_EMAGGABLE_LOCK)
freqlock = RADIO_FREQENCY_UNLOCKED
if(keylock == RADIO_KEYSLOT_EMAGGABLE_LOCK)
keylock = RADIO_KEYSLOT_UNLOCKED
obj_flags |= EMAGGED
return TRUE
/obj/item/radio/intercom/update_icon_state()
icon_state = on ? initial(icon_state) : icon_off
@@ -221,8 +235,7 @@
pixel_shift = 26
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 2)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom, 27)
// Used in the confessional booth in the chapel, locked to the confessional frequency and hides voices
/obj/item/radio/intercom/chapel
name = "Confessional intercom"
desc = "Talk through this... to confess your many sins. Conceals your voice, to keep them secret."
@@ -231,9 +244,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom, 27)
/obj/item/radio/intercom/chapel/Initialize(mapload)
. = ..()
set_frequency(1481)
set_frequency(FREQ_CONFESSIONAL)
set_broadcasting(TRUE)
// Special type of intercom for use in the bridge that can tune into any frequency and has loudmic (NOT FOR PUBLIC AREAS)
/obj/item/radio/intercom/command
name = "command intercom"
desc = "The command's special free-frequency intercom. It's a versatile tool that can be tuned to any frequency, granting you access to channels you're not supposed to be on. Plus, it comes equipped with a built-in voice amplifier for crystal-clear communication."
@@ -242,12 +256,50 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom, 27)
command = TRUE
icon_off = "intercom_command-p"
// Set of intercoms for use in interrogation. Interior one starts broadcasting, exterior one hides voices.
/obj/item/radio/intercom/interrogation
name = "interrogation intercom"
abstract_type = /obj/item/radio/intercom/interrogation
freqlock = RADIO_FREQENCY_LOCKED
/obj/item/radio/intercom/interrogation/Initialize(mapload)
. = ..()
set_frequency(FREQ_INTERROGATION)
/obj/item/radio/intercom/interrogation/inside
desc = "An intercom that broadcasts any ongoing interrogation to someone that's probably taking notes."
/obj/item/radio/intercom/interrogation/inside/Initialize(mapload)
. = ..()
set_broadcasting(TRUE)
set_listening(FALSE)
/obj/item/radio/intercom/interrogation/outside
desc = "An intercom that allows communication with the inside of the interrogation room, while scrambling voices for \"privacy\"."
anonymize = TRUE
// Subtype that simply has freerange enabled
/obj/item/radio/intercom/freerange
name = "free-range intercom"
desc = "A special intercom that can be tuned to any frequency, bypassing encryption."
freerange = TRUE
// For use in the AI core to allow the AI to tune into any encrypted frequency if comms are down
/obj/item/radio/intercom/freerange/ai_core
name = "\improper AI free-range intercom"
/obj/item/radio/intercom/freerange/ai_core/Initialize(mapload)
. = ..()
set_listening(FALSE)
// Intercom with loudmic and innate syndicate channel access
/obj/item/radio/intercom/syndicate
name = "syndicate intercom"
desc = "Talk smack through this."
command = TRUE
special_channels = RADIO_SPECIAL_SYNDIE
// Syndicate intercom that also has freefrange on top of syndicate channel
/obj/item/radio/intercom/syndicate/freerange
name = "syndicate wide-band intercom"
desc = "A custom-made Syndicate-issue intercom used to transmit on all Nanotrasen frequencies. Particularly expensive."
@@ -258,9 +310,99 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom, 27)
desc = "Talk through this to talk to whoever is in this facility with you."
freerange = TRUE
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/prison, 27)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/chapel, 27)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/command, 27)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/syndicate, 27)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/syndicate/freerange, 27)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/mi13, 27)
/obj/item/radio/intercom/ai_private
name = "\improper AI private intercom"
desc = "An intercom primarily used for a private line directly to the station's AI."
/obj/item/radio/intercom/ai_private/Initialize(mapload)
. = ..()
set_frequency(FREQ_AI_PRIVATE)
// For use in AI uploads: Tuned to AI private, actively broadcasting and relaying
/obj/item/radio/intercom/ai_private/broadcasting
/obj/item/radio/intercom/ai_private/broadcasting/Initialize(mapload)
. = ..()
set_broadcasting(TRUE)
// For use in AI chambers: Tuned to AI private, free-range allowed, otherwise doesn't broadcast or relay
/obj/item/radio/intercom/ai_private/freerange
desc = parent_type::desc + " This one can be tuned to any frequency, bypassing encryption."
freerange = TRUE
/obj/item/radio/intercom/ai_private/freerange/Initialize(mapload)
. = ..()
set_listening(FALSE)
// For use in AI antechambers: Tuned to AI private, actively broadcasting, but not relaying
/obj/item/radio/intercom/ai_private/quiet
/obj/item/radio/intercom/ai_private/quiet/Initialize(mapload)
. = ..()
set_listening(FALSE)
// Subtype that spawns with an encryption key and has a key lock
/obj/item/radio/intercom/departmental
desc = "A station intercom primarily intended for speaking with members of a department."
keylock = RADIO_KEYSLOT_EMAGGABLE_LOCK
abstract_type = /obj/item/radio/intercom/departmental
/obj/item/radio/intercom/departmental/Initialize(mapload)
. = ..()
if(length(keyslot?.channels) >= 1)
set_frequency(GLOB.default_radio_channels[keyslot.channels[1]])
/obj/item/radio/intercom/departmental/cargo
name = "cargo intercom"
keyslot = /obj/item/encryptionkey/headset_cargo
/obj/item/radio/intercom/departmental/command
name = "command intercom"
keyslot = /obj/item/encryptionkey/headset_com
/obj/item/radio/intercom/departmental/engineering
name = "engineering intercom"
keyslot = /obj/item/encryptionkey/headset_eng
/obj/item/radio/intercom/departmental/medical
name = "medical intercom"
keyslot = /obj/item/encryptionkey/headset_med
/obj/item/radio/intercom/departmental/science
name = "science intercom"
keyslot = /obj/item/encryptionkey/headset_sci
/obj/item/radio/intercom/departmental/security
name = "security intercom"
keyslot = /obj/item/encryptionkey/headset_sec
/obj/item/radio/intercom/departmental/service
name = "service intercom"
keyslot = /obj/item/encryptionkey/headset_service
#define INTERCOM_OFFSET 27
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/prison, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/chapel, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/ai_private, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/ai_private/broadcasting, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/ai_private/freerange, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/ai_private/quiet, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/command, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/interrogation/inside, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/interrogation/outside, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/freerange, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/freerange/ai_core, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/syndicate, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/syndicate/freerange, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/mi13, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/departmental/cargo, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/departmental/command, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/departmental/engineering, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/departmental/medical, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/departmental/science, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/departmental/security, INTERCOM_OFFSET)
MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/departmental/service, INTERCOM_OFFSET)
#undef INTERCOM_OFFSET
+11 -1
View File
@@ -56,6 +56,8 @@
var/subspace_switchable = FALSE
/// Frequency lock to stop the user from untuning specialist radios.
var/freqlock = RADIO_FREQENCY_UNLOCKED
/// Locks the keyslot to prevent removing the encryption key from specialist radios.
var/keylock = RADIO_KEYSLOT_UNLOCKED
/// If true, broadcasts will be large and BOLD.
var/use_command = FALSE
/// If true, use_command can be toggled at will.
@@ -599,6 +601,14 @@
return ITEM_INTERACT_SUCCESS
/obj/item/radio/screwdriver_act(mob/living/user, obj/item/tool)
switch(keylock)
if(RADIO_KEYSLOT_LOCKED)
to_chat(user, span_warning("The screws locking [src]'s keyslot are stripped, and can't be removed."))
return ITEM_INTERACT_BLOCKING
if(RADIO_KEYSLOT_EMAGGABLE_LOCK)
to_chat(user, span_warning("The screws locking [src]'s keyslot are fastened tight, and likely can't be removed without some kind of magnet..."))
return ITEM_INTERACT_BLOCKING
var/list/removed_keys = remove_keys(user)
if(length(removed_keys) > 1)
to_chat(user, span_notice("You remove the encryption keys from [src]."))
@@ -631,7 +641,7 @@
if(keyslot)
loc.balloon_alert(user, "cannot hold a second key!")
return ITEM_INTERACT_BLOCKING
if(freqlock)
if(freqlock || keylock)
loc.balloon_alert(user, "keyslot is locked!")
return ITEM_INTERACT_BLOCKING