diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql
index d240f567e8c..267581ccfcb 100644
--- a/SQL/paradise_schema.sql
+++ b/SQL/paradise_schema.sql
@@ -288,6 +288,7 @@ CREATE TABLE `player` (
`colourblind_mode` VARCHAR(48) NOT NULL DEFAULT 'None' COLLATE 'utf8mb4_general_ci',
`keybindings` LONGTEXT COLLATE 'utf8mb4_unicode_ci' DEFAULT NULL,
`server_region` VARCHAR(32) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci',
+ `muted_adminsounds_ckeys` MEDIUMTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci',
PRIMARY KEY (`id`),
UNIQUE KEY `ckey` (`ckey`),
KEY `lastseen` (`lastseen`),
diff --git a/SQL/updates/45-46.sql b/SQL/updates/45-46.sql
new file mode 100644
index 00000000000..8c1443788b4
--- /dev/null
+++ b/SQL/updates/45-46.sql
@@ -0,0 +1,4 @@
+# Updating SQL from 45 to 46 -AffectedArc07
+# Adds a way to mute soundfiles from specific admins
+ALTER TABLE `player`
+ ADD COLUMN `muted_adminsounds_ckeys` MEDIUMTEXT NULL DEFAULT NULL AFTER `server_region`;
diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm
index 6dee5bb4c27..374754e7f3d 100644
--- a/code/__DEFINES/misc_defines.dm
+++ b/code/__DEFINES/misc_defines.dm
@@ -380,7 +380,7 @@
#define INVESTIGATE_BOMB "bombs"
// The SQL version required by this version of the code
-#define SQL_VERSION 45
+#define SQL_VERSION 46
// Vending machine stuff
#define CAT_NORMAL 1
diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm
index 6f00c39a459..634485dabc0 100644
--- a/code/modules/admin/verbs/playsound.dm
+++ b/code/modules/admin/verbs/playsound.dm
@@ -26,14 +26,24 @@ GLOBAL_LIST_EMPTY(sounds_cache)
if(alert("Are you sure?\nSong: [S]\nNow you can also play this sound using \"Play Server Sound\".", "Confirmation request" ,"Play", "Cancel") == "Cancel")
return
+ if(holder.fakekey)
+ if(alert("Playing this sound will expose your real ckey despite being in stealth mode. You sure?", "Double check" ,"Play", "Cancel") == "Cancel")
+ return
+
+
log_admin("[key_name(src)] played sound [S]")
message_admins("[key_name_admin(src)] played sound [S]", 1)
for(var/mob/M in GLOB.player_list)
if(M.client.prefs.sound & SOUND_MIDI)
+ if(ckey in M.client.prefs.admin_sound_ckey_ignore)
+ continue // This player has this admin muted
if(isnewplayer(M) && (M.client.prefs.sound & SOUND_LOBBY))
M.stop_sound_channel(CHANNEL_LOBBYMUSIC)
uploaded_sound.volume = 100 * M.client.prefs.get_channel_volume(CHANNEL_ADMIN)
+
+ var/this_uid = M.client.UID()
+ to_chat(M, "[ckey] played [S] (SILENCE) (ALWAYS SILENCE THIS ADMIN)")
SEND_SOUND(M, uploaded_sound)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Global Sound") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 250e1768c0e..2fb3ffa2408 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -172,6 +172,18 @@
switch(href_list["action"])
if("openLink")
src << link(href_list["link"])
+ return
+
+ if("silenceSound")
+ usr.stop_sound_channel(CHANNEL_ADMIN)
+ return
+
+ if("muteAdmin")
+ usr.stop_sound_channel(CHANNEL_ADMIN)
+ prefs.admin_sound_ckey_ignore |= href_list["a"]
+ to_chat(usr, "You will no longer hear admin playsounds from [href_list["a"]]. To remove them, go to Preferences --> Manage Admin Sound Mutes.")
+ prefs.save_preferences(src)
+ return
//fun fact: Topic() acts like a verb and is executed at the end of the tick like other verbs. So we have to queue it if the server is
//overloaded
diff --git a/code/modules/client/login_processing/10-load_preferences.dm b/code/modules/client/login_processing/10-load_preferences.dm
index 8d6e506e34a..e503a993d2b 100644
--- a/code/modules/client/login_processing/10-load_preferences.dm
+++ b/code/modules/client/login_processing/10-load_preferences.dm
@@ -27,7 +27,8 @@
ghost_darkness_level,
colourblind_mode,
keybindings,
- server_region
+ server_region,
+ muted_adminsounds_ckeys
FROM player
WHERE ckey=:ckey"}, list(
"ckey" = C.ckey
diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm
index c72572653ca..8216fffda1e 100644
--- a/code/modules/client/preference/preferences.dm
+++ b/code/modules/client/preference/preferences.dm
@@ -126,6 +126,8 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
var/list/keybindings_overrides = null
/// Player's region override for routing optimisation
var/server_region = null
+ /// List of admin ckeys this player wont hear sounds from
+ var/list/admin_sound_ckey_ignore = list()
/datum/preferences/New(client/C, datum/db_query/Q) // Process our query
parent = C
diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm
index 0e9c4a6eb40..2d1719cf15d 100644
--- a/code/modules/client/preference/preferences_mysql.dm
+++ b/code/modules/client/preference/preferences_mysql.dm
@@ -3,6 +3,7 @@
// Check ../login_processing/10-load_preferences.dm
//general preferences
+ var/raw_muted_admins
while(query.NextRow())
ooccolor = query.item[1]
UI_style = query.item[2]
@@ -27,6 +28,7 @@
colourblind_mode = query.item[21]
keybindings = init_keybindings(raw = query.item[22])
server_region = query.item[23]
+ raw_muted_admins = query.item[24]
lastchangelog_2 = lastchangelog // Clone please
@@ -50,6 +52,12 @@
ghost_darkness_level = sanitize_integer(ghost_darkness_level, 0, 255, initial(ghost_darkness_level))
colourblind_mode = sanitize_inlist(colourblind_mode, list(COLOURBLIND_MODE_NONE, COLOURBLIND_MODE_DEUTER, COLOURBLIND_MODE_PROT, COLOURBLIND_MODE_TRIT), COLOURBLIND_MODE_NONE)
+ if(length(raw_muted_admins))
+ try
+ admin_sound_ckey_ignore = json_decode(raw_muted_admins)
+ catch
+ admin_sound_ckey_ignore = list() // Invalid JSON, handle safely please
+
// Sanitize the region
if(!(server_region in GLOB.configuration.system.region_map))
server_region = null // This region doesnt exist anymore
@@ -89,7 +97,8 @@
ghost_darkness_level=:ghost_darkness_level,
colourblind_mode=:colourblind_mode,
keybindings=:keybindings,
- server_region=:server_region
+ server_region=:server_region,
+ muted_adminsounds_ckeys=:muted_adminsounds_ckeys
WHERE ckey=:ckey"}, list(
// OH GOD THE PARAMETERS
"ooccolour" = ooccolor,
@@ -115,6 +124,7 @@
"keybindings" = json_encode(keybindings_overrides),
"ckey" = C.ckey,
"server_region" = server_region,
+ "muted_adminsounds_ckeys" = json_encode(admin_sound_ckey_ignore),
))
if(!query.warn_execute())
diff --git a/code/modules/client/preference/preferences_toggles.dm b/code/modules/client/preference/preferences_toggles.dm
index c62c400543b..2320b4edb4d 100644
--- a/code/modules/client/preference/preferences_toggles.dm
+++ b/code/modules/client/preference/preferences_toggles.dm
@@ -373,3 +373,20 @@
prefs.toggles2 ^= PREFTOGGLE_2_DANCE_DISCO
prefs.save_preferences(src)
to_chat(usr, "You will [(prefs.toggles2 & PREFTOGGLE_2_DANCE_DISCO) ? "now" : "no longer"] dance to the radiant dance machine.")
+
+/client/verb/manage_adminsound_mutes()
+ set name = "Manage Admin Sound Mutes"
+ set category = "Preferences"
+ set desc = "Manage admins that you wont hear played audio from"
+
+ if(!length(prefs.admin_sound_ckey_ignore))
+ to_chat(usr, "You have no admins with muted sounds.")
+ return
+
+ var/choice = input(usr, "Select an admin to unmute sounds from.", "Pick an admin") as null|anything in prefs.admin_sound_ckey_ignore
+ if(!choice)
+ return
+
+ prefs.admin_sound_ckey_ignore -= choice
+ to_chat(usr, "You will now hear sounds from [choice] again.")
+ prefs.save_preferences(src)
diff --git a/config/example/config.toml b/config/example/config.toml
index 1ac63d607aa..59defb26eb2 100644
--- a/config/example/config.toml
+++ b/config/example/config.toml
@@ -145,7 +145,7 @@ ipc_screens = [
# Enable/disable the database on a whole
sql_enabled = false
# SQL version. If this is a mismatch, round start will be delayed
-sql_version = 45
+sql_version = 46
# SQL server address. Can be an IP or DNS name
sql_address = "127.0.0.1"
# SQL server port