From faaa1f15163100d8b84588d398a1be99db7df609 Mon Sep 17 00:00:00 2001
From: Bloop <13398309+vinylspiders@users.noreply.github.com>
Date: Tue, 5 May 2026 14:54:04 -0400
Subject: [PATCH] Ghosts now have (better) runechat (#95843)
## About The Pull Request
Ports our optimizations to the version of ghost runechat introduced by
https://github.com/tgstation/tgstation/pull/95223
Instead of looping through all the mobs a second time it will do it in
deadchat_broadcast(). Also adds a global for if drunechat is
enabled/disabled and an admin verb for toggling it on or off.
still works
## Why It's Good For The Game
Better option for performance
## Changelog
:cl:
code: speeds ghost runechat up a bit, and makes it show as italic
admin: adds a 'toggle dead runechat' admin verb in case you need to
disable it midround for an event or something
/:cl:
---
code/__DEFINES/lag_switch.dm | 4 +++-
code/__HELPERS/mobs.dm | 20 +++++++++++++++-----
code/controllers/subsystem/lag_switch.dm | 2 +-
code/modules/admin/verbs/admingame.dm | 1 +
code/modules/client/verbs/ooc.dm | 1 -
code/modules/mob/mob_say.dm | 7 +------
6 files changed, 21 insertions(+), 14 deletions(-)
diff --git a/code/__DEFINES/lag_switch.dm b/code/__DEFINES/lag_switch.dm
index 2115ce4a5dd..de8e74b79cd 100644
--- a/code/__DEFINES/lag_switch.dm
+++ b/code/__DEFINES/lag_switch.dm
@@ -16,5 +16,7 @@
#define DISABLE_PARALLAX 7
/// Disables footsteps, TRAIT_BYPASS_MEASURES exempted
#define DISABLE_FOOTSTEPS 8
+/// Disables runechat for ghosts
+#define DISABLE_DEAD_RUNECHAT 9
-#define MEASURES_AMOUNT 8 // The total number of switches defined above
+#define MEASURES_AMOUNT 9 // The total number of switches defined above
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 4a9d2e205e2..cea8ed49359 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -363,9 +363,11 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
return spawned_mobs
+#define SEE_DEADCHAT_ADMIN (1<<0)
+#define SEE_DEADCHAT_NORMAL (1<<1)
// Displays a message in deadchat, sent by source. source is not linkified, message is, to avoid stuff like character names to be linkified.
// Automatically gives the class deadsay to the whole message (message + source)
-/proc/deadchat_broadcast(message, source=null, mob/follow_target=null, turf/turf_target=null, speaker_key=null, message_type=DEADCHAT_REGULAR, admin_only=FALSE)
+/proc/deadchat_broadcast(message, source=null, mob/follow_target=null, turf/turf_target=null, speaker_key=null, message_type=DEADCHAT_REGULAR, admin_only=FALSE, original_message)
message = span_deadsay("[source][span_linkify(message)]")
if(admin_only)
@@ -383,13 +385,13 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
if(admin_only)
if(!M.client?.holder)
continue
- var/override = FALSE
+ var/override = NONE
if(M.client?.holder && (chat_toggles & CHAT_DEAD))
- override = TRUE
+ override = SEE_DEADCHAT_ADMIN
if(HAS_TRAIT(M, TRAIT_SIXTHSENSE) && message_type == DEADCHAT_REGULAR)
- override = TRUE
+ override = SEE_DEADCHAT_NORMAL
if(SSticker.current_state == GAME_STATE_FINISHED)
- override = TRUE
+ override = SEE_DEADCHAT_NORMAL
if(isnewplayer(M) && !override)
continue
if(M.stat != DEAD && !override)
@@ -413,6 +415,7 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
if(isobserver(M))
var/rendered_message = message
+ override = SEE_DEADCHAT_NORMAL
if(follow_target)
var/F
@@ -429,6 +432,13 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
else
to_chat(M, message, avoid_highlighting = speaker_key == M.key)
+ // Ghost runechat
+ if(original_message && ((override & SEE_DEADCHAT_NORMAL) || M.see_invisible >= follow_target.invisibility) && (!SSlag_switch.measures[DISABLE_DEAD_RUNECHAT] || HAS_TRAIT(M, TRAIT_BYPASS_MEASURES)) && M.runechat_prefs_check(M))
+ M.create_chat_message(follow_target, /datum/language/common, original_message, list(SPAN_ITALICS))
+#undef SEE_DEADCHAT_ADMIN
+#undef SEE_DEADCHAT_NORMAL
+
+
//Used in chemical_mob_spawn. Generates a random mob based on a given gold_core_spawnable value.
/proc/create_random_mob(spawn_location, mob_class = HOSTILE_SPAWN)
var/static/list/mob_spawn_meancritters = list() // list of possible hostile mobs
diff --git a/code/controllers/subsystem/lag_switch.dm b/code/controllers/subsystem/lag_switch.dm
index 70979b40816..f70b3e70709 100644
--- a/code/controllers/subsystem/lag_switch.dm
+++ b/code/controllers/subsystem/lag_switch.dm
@@ -10,7 +10,7 @@ SUBSYSTEM_DEF(lag_switch)
/// List of bools corresponding to code/__DEFINES/lag_switch.dm
var/static/list/measures[MEASURES_AMOUNT]
/// List of measures that toggle automatically
- var/list/auto_measures = list(DISABLE_GHOST_ZOOM_TRAY, DISABLE_RUNECHAT, DISABLE_USR_ICON2HTML, DISABLE_PARALLAX, DISABLE_FOOTSTEPS)
+ var/list/auto_measures = list(DISABLE_GHOST_ZOOM_TRAY, DISABLE_RUNECHAT, DISABLE_USR_ICON2HTML, DISABLE_PARALLAX, DISABLE_FOOTSTEPS, DISABLE_DEAD_RUNECHAT)
/// Timer ID for the automatic veto period
var/veto_timer_id
/// Cooldown between say verb uses when slowmode is enabled
diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm
index f1c1ae14af1..e7b91726099 100644
--- a/code/modules/admin/verbs/admingame.dm
+++ b/code/modules/admin/verbs/admingame.dm
@@ -484,6 +484,7 @@ ADMIN_VERB(lag_switch_panel, R_ADMIN, "Show Lag Switches", "Display the controls
dat += "
Measures below can be bypassed with a special trait
"
dat += "Slowmode say verb (informs world): [SSlag_switch.measures[SLOWMODE_SAY] ? "On" : "Off"]
"
dat += "Disable runechat: [SSlag_switch.measures[DISABLE_RUNECHAT] ? "On" : "Off"] - trait applies to speaker
"
+ dat += "Disable dead runechat: [SSlag_switch.measures[DISABLE_DEAD_RUNECHAT] ? "On" : "Off"] - trait applies to speaker
"
dat += "Disable examine icons: [SSlag_switch.measures[DISABLE_USR_ICON2HTML] ? "On" : "Off"] - trait applies to examiner
"
dat += "Disable parallax: [SSlag_switch.measures[DISABLE_PARALLAX] ? "On" : "Off"] - trait applies to character
"
dat += "Disable footsteps: [SSlag_switch.measures[DISABLE_FOOTSTEPS] ? "On" : "Off"] - trait applies to character
"
diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm
index a25299089e2..ce33331c6e4 100644
--- a/code/modules/client/verbs/ooc.dm
+++ b/code/modules/client/verbs/ooc.dm
@@ -133,7 +133,6 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
else
GLOB.dooc_allowed = !GLOB.dooc_allowed
-
/client/proc/set_ooc()
set name = "Set Player OOC Color"
set desc = "Modifies player OOC Color"
diff --git a/code/modules/mob/mob_say.dm b/code/modules/mob/mob_say.dm
index 920439d1091..901fd8fd132 100644
--- a/code/modules/mob/mob_say.dm
+++ b/code/modules/mob/mob_say.dm
@@ -159,12 +159,7 @@
var/displayed_key = key
if(client?.holder?.fakekey)
displayed_key = null
- deadchat_broadcast(rendered, source, follow_target = src, speaker_key = displayed_key)
- for(var/mob/mobs_hearing as anything in GLOB.player_list)
- if(SSticker.current_state != GAME_STATE_FINISHED && (mobs_hearing.see_invisible < invisibility || !isdead(mobs_hearing)))
- continue
- if(runechat_prefs_check(mobs_hearing))
- mobs_hearing.create_chat_message(src, /datum/language/common, message)
+ deadchat_broadcast(rendered, source, follow_target = src, speaker_key = displayed_key, original_message = message)
///Check if this message is an emote
/mob/proc/check_emote(message, forced)