diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 50ed3ff6633..f90722e9b1a 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -296,6 +296,7 @@ GLOBAL_LIST_INIT(pda_styles, sortList(list(MONO, VT, ORBITRON, SHARE)))
#define DEADCHAT_DEATHRATTLE "deathrattle"
#define DEADCHAT_LAWCHANGE "lawchange"
#define DEADCHAT_REGULAR "regular-deadchat"
+#define DEADCHAT_LOGIN_LOGOUT "loginlogout"
// Bluespace shelter deploy checks
#define SHELTER_DEPLOY_ALLOWED "allowed"
diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index 192d04f1c84..00984f23953 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -38,8 +38,9 @@
#define CHAT_GHOSTRADIO (1<<9)
#define CHAT_BANKCARD (1<<10)
#define CHAT_GHOSTLAWS (1<<11)
+#define CHAT_LOGIN_LOGOUT (1<<12)
-#define TOGGLES_DEFAULT_CHAT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_PULLR|CHAT_GHOSTWHISPER|CHAT_GHOSTPDA|CHAT_GHOSTRADIO|CHAT_BANKCARD|CHAT_GHOSTLAWS)
+#define TOGGLES_DEFAULT_CHAT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_PULLR|CHAT_GHOSTWHISPER|CHAT_GHOSTPDA|CHAT_GHOSTRADIO|CHAT_BANKCARD|CHAT_GHOSTLAWS|CHAT_LOGIN_LOGOUT)
#define PARALLAX_INSANE -1 //for show offs
#define PARALLAX_HIGH 0 //default.
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 104c9610f2e..784e9df4c99 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -461,8 +461,9 @@ GLOBAL_LIST_EMPTY(species_list)
// 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)
+/proc/deadchat_broadcast(message, source=null, mob/follow_target=null, turf/turf_target=null, speaker_key=null, message_type=DEADCHAT_REGULAR, admin_only=FALSE)
message = "[source][message]"
+
for(var/mob/M in GLOB.player_list)
var/chat_toggles = TOGGLES_DEFAULT_CHAT
var/toggles = TOGGLES_DEFAULT
@@ -472,8 +473,11 @@ GLOBAL_LIST_EMPTY(species_list)
chat_toggles = prefs.chat_toggles
toggles = prefs.toggles
ignoring = prefs.ignoring
-
-
+ if(admin_only)
+ if (!M.client.holder)
+ return
+ else
+ message += " (This is viewable to admins only)."
var/override = FALSE
if(M.client.holder && (chat_toggles & CHAT_DEAD))
override = TRUE
@@ -498,6 +502,9 @@ GLOBAL_LIST_EMPTY(species_list)
if(DEADCHAT_LAWCHANGE)
if(!(chat_toggles & CHAT_GHOSTLAWS))
continue
+ if(DEADCHAT_LOGIN_LOGOUT)
+ if(!(chat_toggles & CHAT_LOGIN_LOGOUT))
+ continue
if(isobserver(M))
var/rendered_message = message
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 0ff99cc3d60..0ab003422bf 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -248,10 +248,8 @@ Turf and target are separate in case you want to teleport some distance from a t
continue
if(M.client && M.client.holder && M.client.holder.fakekey) //stealthmins
continue
- var/name = avoid_assoc_duplicate_keys(M.name, namecounts)
+ var/name = avoid_assoc_duplicate_keys(M.name, namecounts) + M.get_realname_string()
- if(M.real_name && M.real_name != M.name)
- name += " \[[M.real_name]\]"
if(M.stat == DEAD && specify_dead_role)
if(isobserver(M))
name += " \[ghost\]"
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index cf1119434e4..0bea6c74f3f 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -282,8 +282,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
else
message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(C)] (no longer logged in). ")
log_admin_private("Notice: [key_name(src)] has the same [matches] as [key_name(C)] (no longer logged in).")
-
+ var/reconnecting = FALSE
if(GLOB.player_details[ckey])
+ reconnecting = TRUE
player_details = GLOB.player_details[ckey]
player_details.byond_version = full_version
else
@@ -380,7 +381,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
add_admin_verbs()
to_chat(src, get_message_output("memo"))
adminGreet()
-
+ if (mob && reconnecting)
+ var/stealth_admin = mob.client?.holder?.fakekey
+ var/announce_leave = mob.client?.prefs?.broadcast_login_logout
+ if (!stealth_admin)
+ deadchat_broadcast(" has reconnected.", "[mob][mob.get_realname_string()]", follow_target = mob, turf_target = get_turf(mob), message_type = DEADCHAT_LOGIN_LOGOUT, admin_only=!announce_leave)
add_verbs_from_config()
var/cached_player_age = set_client_age_from_db(tdata) //we have to cache this because other shit may change it and we need it's current value now down below.
if (isnum(cached_player_age) && cached_player_age == -1) //first connection
@@ -450,6 +455,12 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
return ..()
/client/Destroy()
+ if(mob)
+ var/stealth_admin = mob.client?.holder?.fakekey
+ var/announce_join = mob.client?.prefs?.broadcast_login_logout
+ if (!stealth_admin)
+ deadchat_broadcast(" has disconnected.", "[mob][mob.get_realname_string()]", follow_target = mob, turf_target = get_turf(mob), message_type = DEADCHAT_LOGIN_LOGOUT, admin_only=!announce_join)
+
GLOB.clients -= src
GLOB.directory -= ckey
log_access("Logout: [key_name(src)]")
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 93f7c04b1f7..76d78714166 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -137,6 +137,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/body_type
/// If we have persistent scars enabled
var/persistent_scars = TRUE
+ ///If we want to broadcast deadchat connect/disconnect messages
+ var/broadcast_login_logout = TRUE
/datum/preferences/New(client/C)
parent = C
@@ -610,6 +612,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Ghosts of Others: [button_name]
"
dat += "
"
+ dat += "Broadcast Login/Logout: [broadcast_login_logout ? "Broadcast" : "Silent"]
"
+ dat += "See Login/Logout Messages: [(chat_toggles & CHAT_LOGIN_LOGOUT) ? "Allowed" : "Muted"]
"
+ dat += "
"
+
dat += "Income Updates: [(chat_toggles & CHAT_BANKCARD) ? "Allowed" : "Muted"]
"
dat += "
"
@@ -1776,6 +1782,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("ghost_laws")
chat_toggles ^= CHAT_GHOSTLAWS
+ if("hear_login_logout")
+ chat_toggles ^= CHAT_LOGIN_LOGOUT
+
+ if("broadcast_login_logout")
+ broadcast_login_logout = !broadcast_login_logout
+
if("income_pings")
chat_toggles ^= CHAT_BANKCARD
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index b69491f63a3..b9c9eaade82 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -166,6 +166,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
READ_FILE(S["max_chat_length"], max_chat_length)
READ_FILE(S["see_chat_non_mob"] , see_chat_non_mob)
READ_FILE(S["see_rc_emotes"] , see_rc_emotes)
+ READ_FILE(S["broadcast_login_logout"] , broadcast_login_logout)
+
READ_FILE(S["tgui_fancy"], tgui_fancy)
READ_FILE(S["tgui_lock"], tgui_lock)
READ_FILE(S["buttons_locked"], buttons_locked)
@@ -226,6 +228,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
max_chat_length = sanitize_integer(max_chat_length, 1, CHAT_MESSAGE_MAX_LENGTH, initial(max_chat_length))
see_chat_non_mob = sanitize_integer(see_chat_non_mob, FALSE, TRUE, initial(see_chat_non_mob))
see_rc_emotes = sanitize_integer(see_rc_emotes, FALSE, TRUE, initial(see_rc_emotes))
+ broadcast_login_logout = sanitize_integer(broadcast_login_logout, FALSE, TRUE, initial(broadcast_login_logout))
tgui_fancy = sanitize_integer(tgui_fancy, FALSE, TRUE, initial(tgui_fancy))
tgui_lock = sanitize_integer(tgui_lock, FALSE, TRUE, initial(tgui_lock))
buttons_locked = sanitize_integer(buttons_locked, FALSE, TRUE, initial(buttons_locked))
@@ -289,6 +292,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["max_chat_length"], max_chat_length)
WRITE_FILE(S["see_chat_non_mob"], see_chat_non_mob)
WRITE_FILE(S["see_rc_emotes"], see_rc_emotes)
+ WRITE_FILE(S["broadcast_login_logout"], broadcast_login_logout)
WRITE_FILE(S["tgui_fancy"], tgui_fancy)
WRITE_FILE(S["tgui_lock"], tgui_lock)
WRITE_FILE(S["buttons_locked"], buttons_locked)
diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm
index 24ff74bd94f..dadba09ca40 100644
--- a/code/modules/client/preferences_toggles.dm
+++ b/code/modules/client/preferences_toggles.dm
@@ -96,6 +96,17 @@ TOGGLE_CHECKBOX(/datum/verbs/menu/settings/ghost/chatterbox, toggle_ghost_laws)(
/datum/verbs/menu/settings/ghost/chatterbox/toggle_ghost_laws/Get_checked(client/C)
return C.prefs.chat_toggles & CHAT_GHOSTLAWS
+TOGGLE_CHECKBOX(/datum/verbs/menu/settings/ghost/chatterbox, toggle_hear_login_logout)()
+ set name = "Show/Hide Login/Logout messages"
+ set category = "Preferences"
+ set desc = "As a ghost, see when someone reconnects or disconnects"
+ usr.client.prefs.chat_toggles ^= CHAT_LOGIN_LOGOUT
+ to_chat(usr, "As a ghost, you will now [(usr.client.prefs.chat_toggles & CHAT_LOGIN_LOGOUT) ? "be notified" : "no longer be notified"] when someone disconnects or reconnects.")
+ usr.client.prefs.save_preferences()
+ SSblackbox.record_feedback("nested tally", "preferences_verb", 1, list("Toggle Hearing Login/Logout", "[usr.client.prefs.chat_toggles & CHAT_LOGIN_LOGOUT ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+/datum/verbs/menu/settings/ghost/chatterbox/toggle_hear_login_logout/Get_checked(client/C)
+ return C.prefs.chat_toggles & CHAT_LOGIN_LOGOUT
+
/datum/verbs/menu/settings/ghost/chatterbox/events
name = "Events"
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 12fb1279b47..a7b9fd7ba3d 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -286,6 +286,12 @@
if(hud_used?.action_intent)
hud_used.action_intent.icon_state = "[a_intent]"
+///Returns a mob's real name between brackets. Useful when you want to display a mob's name alongside their real name
+/mob/proc/get_realname_string()
+ if(real_name && real_name != name)
+ return " \[[real_name]\]"
+ return ""
+
///Checks if the mob is able to see or not. eye_blind is temporary blindness, the trait is if they're permanently blind.
/mob/proc/is_blind()
SHOULD_BE_PURE(TRUE)
diff --git a/modular_skyrat/modules/customization/modules/client/preferences.dm b/modular_skyrat/modules/customization/modules/client/preferences.dm
index 00e666ff3da..345c0eb4e8f 100644
--- a/modular_skyrat/modules/customization/modules/client/preferences.dm
+++ b/modular_skyrat/modules/customization/modules/client/preferences.dm
@@ -138,6 +138,8 @@
/// If we have persistent scars enabled
var/persistent_scars = TRUE
+ ///If we want to broadcast deadchat connect/disconnect messages
+ var/broadcast_login_logout = FALSE
/// We have 5 slots for persistent scars, if enabled we pick a random one to load (empty by default) and scars at the end of the shift if we survived as our original person
var/list/scars_list = list("1" = "", "2" = "", "3" = "", "4" = "", "5" = "")
/// Which of the 5 persistent scar slots we randomly roll to load for this round, if enabled. Actually rolled in [/datum/preferences/proc/load_character(slot)]
@@ -932,6 +934,10 @@
dat += "Ghosts of Others: [button_name]
"
dat += "
"
+ dat += "Broadcast Login/Logout: [broadcast_login_logout ? "Broadcast" : "Silent"]
"
+ dat += "See Login/Logout Messages: [(chat_toggles & CHAT_LOGIN_LOGOUT) ? "Allowed" : "Muted"]
"
+ dat += "
"
+
dat += "Income Updates: [(chat_toggles & CHAT_BANKCARD) ? "Allowed" : "Muted"]
"
dat += "
"
@@ -2526,6 +2532,12 @@
if("ghost_laws")
chat_toggles ^= CHAT_GHOSTLAWS
+ if("hear_login_logout")
+ chat_toggles ^= CHAT_LOGIN_LOGOUT
+
+ if("broadcast_login_logout")
+ broadcast_login_logout = !broadcast_login_logout
+
if("income_pings")
chat_toggles ^= CHAT_BANKCARD
diff --git a/modular_skyrat/modules/customization/modules/client/preferences_savefile.dm b/modular_skyrat/modules/customization/modules/client/preferences_savefile.dm
index 840aaf88325..4bc8caa63e1 100644
--- a/modular_skyrat/modules/customization/modules/client/preferences_savefile.dm
+++ b/modular_skyrat/modules/customization/modules/client/preferences_savefile.dm
@@ -141,6 +141,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
READ_FILE(S["max_chat_length"], max_chat_length)
READ_FILE(S["see_chat_non_mob"] , see_chat_non_mob)
READ_FILE(S["see_rc_emotes"] , see_rc_emotes)
+ READ_FILE(S["broadcast_login_logout"] , broadcast_login_logout)
+
READ_FILE(S["tgui_fancy"], tgui_fancy)
READ_FILE(S["tgui_lock"], tgui_lock)
READ_FILE(S["buttons_locked"], buttons_locked)
@@ -195,6 +197,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
max_chat_length = sanitize_integer(max_chat_length, 1, CHAT_MESSAGE_MAX_LENGTH, initial(max_chat_length))
see_chat_non_mob = sanitize_integer(see_chat_non_mob, FALSE, TRUE, initial(see_chat_non_mob))
see_rc_emotes = sanitize_integer(see_rc_emotes, FALSE, TRUE, initial(see_rc_emotes))
+ broadcast_login_logout = sanitize_integer(broadcast_login_logout, FALSE, TRUE, initial(broadcast_login_logout))
tgui_fancy = sanitize_integer(tgui_fancy, FALSE, TRUE, initial(tgui_fancy))
tgui_lock = sanitize_integer(tgui_lock, FALSE, TRUE, initial(tgui_lock))
buttons_locked = sanitize_integer(buttons_locked, FALSE, TRUE, initial(buttons_locked))
@@ -241,6 +244,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["max_chat_length"], max_chat_length)
WRITE_FILE(S["see_chat_non_mob"], see_chat_non_mob)
WRITE_FILE(S["see_rc_emotes"], see_rc_emotes)
+ WRITE_FILE(S["broadcast_login_logout"], broadcast_login_logout)
WRITE_FILE(S["tgui_fancy"], tgui_fancy)
WRITE_FILE(S["tgui_lock"], tgui_lock)
WRITE_FILE(S["buttons_locked"], buttons_locked)