diff --git a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm
index 8caf205817f6..62c770e6322e 100644
--- a/code/__DEFINES/logging.dm
+++ b/code/__DEFINES/logging.dm
@@ -5,6 +5,9 @@
/// Admins can still manually request a re-render
#define LOG_UPDATE_TIMEOUT 5 SECONDS
+// The maximum number of entries allowed in the signaler investigate log, keep this relatively small to prevent performance issues when an admin tries to query it
+#define INVESTIGATE_SIGNALER_LOG_MAX_LENGTH 500
+
//Investigate logging defines
#define INVESTIGATE_ACCESSCHANGES "id_card_changes"
#define INVESTIGATE_ATMOS "atmos"
diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm
index 914665d17987..8a57ad13ea7e 100644
--- a/code/_globalvars/logging.dm
+++ b/code/_globalvars/logging.dm
@@ -61,9 +61,17 @@ GLOBAL_PROTECT(admin_activities)
GLOBAL_LIST_EMPTY(bombers)
GLOBAL_PROTECT(bombers)
-/// All signals here in format: "[src] used [REF(src)] @ location [src.loc]: [freq]/[code]"
-GLOBAL_LIST_EMPTY(lastsignalers)
-GLOBAL_PROTECT(lastsignalers)
+/// Investigate log for signaler usage, use the add_to_signaler_investigate_log proc
+GLOBAL_LIST_EMPTY(investigate_signaler)
+GLOBAL_PROTECT(investigate_signaler)
+
+/// Used to add a text log to the signaler investigation log.
+/// Do not add to the list directly; if the list is too large it can cause lag when an admin tries to view it.
+/proc/add_to_signaler_investigate_log(text)
+ var/log_length = length(GLOB.investigate_signaler)
+ if(log_length >= INVESTIGATE_SIGNALER_LOG_MAX_LENGTH)
+ GLOB.investigate_signaler = GLOB.investigate_signaler.Copy((INVESTIGATE_SIGNALER_LOG_MAX_LENGTH - log_length) + 2)
+ GLOB.investigate_signaler += list(text)
/// Stores who uploaded laws to which silicon-based lifeform, and what the law was
GLOBAL_LIST_EMPTY(lawchanges)
diff --git a/code/modules/admin/verbs/list_exposer.dm b/code/modules/admin/verbs/list_exposer.dm
index c2c48963051e..00a5960b3658 100644
--- a/code/modules/admin/verbs/list_exposer.dm
+++ b/code/modules/admin/verbs/list_exposer.dm
@@ -13,8 +13,8 @@
if(!SSticker.HasRoundStarted())
tgui_alert(usr, "The game hasn't started yet!")
return
- var/data = "Showing last [length(GLOB.lastsignalers)] signalers.
"
- for(var/entry in GLOB.lastsignalers)
+ var/data = "Showing last [length(GLOB.investigate_signaler)] signalers."
+ for(var/entry in GLOB.investigate_signaler)
data += "[entry] "
usr << browse(data, "window=lastsignalers;size=800x500")
diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm
index de9a27404972..d38d20790e14 100644
--- a/code/modules/assembly/signaler.dm
+++ b/code/modules/assembly/signaler.dm
@@ -10,15 +10,20 @@
drop_sound = 'sound/items/handling/component_drop.ogg'
pickup_sound = 'sound/items/handling/component_pickup.ogg'
+ /// The code sent by this signaler.
var/code = DEFAULT_SIGNALER_CODE
+ /// The frequency this signaler is set to.
var/frequency = FREQ_SIGNALER
+ /// How long of a cooldown exists on this signaller.
+ var/cooldown_length = 1 SECONDS
+ /// The radio frequency connection this signaler is using.
var/datum/radio_frequency/radio_connection
- ///Holds the mind that commited suicide.
+ /// Holds the mind that commited suicide.
var/datum/mind/suicider
- ///Holds a reference string to the mob, decides how much of a gamer you are.
+ /// Holds a reference string to the mob, decides how much of a gamer you are.
var/suicide_mob
+ /// How many tiles away can you hear when this signaler is used or gets activated.
var/hearing_range = 1
-
/// String containing the last piece of logging data relating to when this signaller has received a signal.
var/last_receive_signal_log
@@ -77,23 +82,26 @@
/obj/item/assembly/signaler/ui_data(mob/user)
var/list/data = list()
data["frequency"] = frequency
+ data["cooldown"] = cooldown_length
data["code"] = code
data["minFrequency"] = MIN_FREE_FREQ
data["maxFrequency"] = MAX_FREE_FREQ
return data
-/obj/item/assembly/signaler/ui_act(action, params)
+/obj/item/assembly/signaler/ui_act(action, params, datum/tgui/ui)
. = ..()
if(.)
return
switch(action)
if("signal")
- if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_SIGNALLER_SEND))
- to_chat(usr, span_warning("[src] is still recharging..."))
- return
- TIMER_COOLDOWN_START(src, COOLDOWN_SIGNALLER_SEND, 1 SECONDS)
+ if(cooldown_length > 0)
+ if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_SIGNALLER_SEND))
+ balloon_alert(ui.user, "recharging!")
+ return
+ TIMER_COOLDOWN_START(src, COOLDOWN_SIGNALLER_SEND, cooldown_length)
INVOKE_ASYNC(src, PROC_REF(signal))
+ balloon_alert(ui.user, "signaled")
. = TRUE
if("freq")
var/new_frequency = sanitize_frequency(unformat_frequency(params["freq"]), TRUE)
@@ -141,10 +149,8 @@
var/time = time2text(world.realtime,"hh:mm:ss")
var/turf/T = get_turf(src)
- var/logging_data
- if(usr)
- logging_data = "[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]"
- GLOB.lastsignalers.Add(logging_data)
+ var/logging_data = "[time] : [key_name(usr)] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]"
+ add_to_signaler_investigate_log(logging_data)
var/datum/signal/signal = new(list("code" = code), logging_data = logging_data)
radio_connection.post_signal(src, signal)
diff --git a/code/modules/modular_computers/file_system/programs/signalcommander.dm b/code/modules/modular_computers/file_system/programs/signalcommander.dm
index 6d636bab370a..e8140b62b17c 100644
--- a/code/modules/modular_computers/file_system/programs/signalcommander.dm
+++ b/code/modules/modular_computers/file_system/programs/signalcommander.dm
@@ -14,6 +14,10 @@
var/signal_code = DEFAULT_SIGNALER_CODE
/// Radio connection datum used by signalers.
var/datum/radio_frequency/radio_connection
+ /// How long do we cooldown before we can send another signal?
+ var/signal_cooldown_time = 1 SECONDS
+ /// Cooldown store
+ COOLDOWN_DECLARE(signal_cooldown)
/datum/computer_file/program/signal_commander/on_start(mob/living/user)
. = ..()
@@ -26,6 +30,7 @@
/datum/computer_file/program/signal_commander/ui_data(mob/user)
var/list/data = list()
data["frequency"] = signal_frequency
+ data["cooldown"] = signal_cooldown_time
data["code"] = signal_code
data["minFrequency"] = MIN_FREE_FREQ
data["maxFrequency"] = MAX_FREE_FREQ
@@ -55,13 +60,18 @@
if(!radio_connection)
return
+ if(!COOLDOWN_FINISHED(src, signal_cooldown))
+ computer.balloon_alert(usr, "cooling down!")
+ return
+
+ COOLDOWN_START(src, signal_cooldown, signal_cooldown_time)
+ computer.balloon_alert(usr, "signaled")
+
var/time = time2text(world.realtime,"hh:mm:ss")
var/turf/T = get_turf(computer)
- var/logging_data
- if(usr)
- logging_data = "[time] : [usr.key] used [computer] @ location ([T.x],[T.y],[T.z]) : [format_frequency(signal_frequency)]/[signal_code]"
- GLOB.lastsignalers.Add(logging_data)
+ var/logging_data = "[time] : [key_name(usr)] used the computer '[initial(computer.name)]' @ location ([T.x],[T.y],[T.z]) : [format_frequency(signal_frequency)]/[signal_code]"
+ add_to_signaler_investigate_log(logging_data)
var/datum/signal/signal = new(list("code" = signal_code), logging_data = logging_data)
radio_connection.post_signal(computer, signal)
@@ -70,4 +80,3 @@
SSradio.remove_object(computer, signal_frequency)
signal_frequency = new_frequency
radio_connection = SSradio.add_object(computer, signal_frequency, RADIO_SIGNALER)
- return
diff --git a/code/modules/wiremod/components/action/radio.dm b/code/modules/wiremod/components/action/radio.dm
index cd13e0e1e451..74b2c54c1b81 100644
--- a/code/modules/wiremod/components/action/radio.dm
+++ b/code/modules/wiremod/components/action/radio.dm
@@ -28,8 +28,17 @@
/// The ckey of the user who used the shell we were placed in, important for signalling logs.
var/owner_ckey = null
+ /// The radio connection we are using to receive signals.
var/datum/radio_frequency/radio_connection
+ /// How long of a cooldown we have before we can send another signal.
+ var/signal_cooldown_time = 1 SECONDS
+
+/obj/item/circuit_component/radio/Initialize(mapload)
+ . = ..()
+ if(signal_cooldown_time > 0)
+ desc = "[desc] It has a [signal_cooldown_time * 0.1] second cooldown between sending signals."
+
/obj/item/circuit_component/radio/register_shell(atom/movable/shell)
parent_shell = shell
var/potential_fingerprints = shell.fingerprintslast
@@ -65,8 +74,10 @@
INVOKE_ASYNC(src, PROC_REF(handle_radio_input), port)
/obj/item/circuit_component/radio/proc/handle_radio_input(datum/port/input/port)
- var/frequency = freq.value
+ if(!TIMER_COOLDOWN_CHECK(parent, COOLDOWN_SIGNALLER_SEND))
+ return
+ var/frequency = freq.value
if(frequency != current_freq)
SSradio.remove_object(src, current_freq)
radio_connection = SSradio.add_object(src, frequency, RADIO_SIGNALER)
@@ -84,7 +95,8 @@
loggable_strings += ": The last fingerprints on the containing shell was [parent_shell.fingerprintslast]."
var/loggable_string = loggable_strings.Join(" ")
- GLOB.lastsignalers.Add(loggable_string)
+ add_to_signaler_investigate_log(loggable_string)
+ TIMER_COOLDOWN_START(parent, COOLDOWN_SIGNALLER_SEND, signal_cooldown_time)
var/datum/signal/signal = new(list("code" = signal_code, "key" = parent?.owner_id), logging_data = loggable_string)
radio_connection.post_signal(src, signal)
diff --git a/tgui/packages/tgui/interfaces/Signaler.jsx b/tgui/packages/tgui/interfaces/Signaler.jsx
index 81ee5a370c81..f3348b081c6c 100644
--- a/tgui/packages/tgui/interfaces/Signaler.jsx
+++ b/tgui/packages/tgui/interfaces/Signaler.jsx
@@ -16,7 +16,7 @@ export const Signaler = (props) => {
export const SignalerContent = (props) => {
const { act, data } = useBackend();
- const { code, frequency, minFrequency, maxFrequency } = data;
+ const { code, frequency, cooldown, minFrequency, maxFrequency } = data;
const color = 'rgba(13, 13, 213, 0.7)';
const backColor = 'rgba(0, 0, 69, 0.5)';
return (
@@ -94,6 +94,7 @@ export const SignalerContent = (props) => {