From 281c72fbccb71625b3e3cb39e7296b9978dbd902 Mon Sep 17 00:00:00 2001
From: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>
Date: Wed, 5 May 2021 02:43:05 +0100
Subject: [PATCH] Who & Adminwho improvements (#15855)
* Who & Adminwho improvements
* Mochi tweaks
* Sabre tweaks
---
code/__HELPERS/text.dm | 19 ++++
code/_globalvars/lists/misc.dm | 3 +
code/controllers/configuration.dm | 31 +++++++
code/game/verbs/who.dm | 149 ++++++++++++++++++++----------
code/game/world.dm | 1 +
code/modules/admin/topic.dm | 2 +
config/example/rank_colours.txt | 11 +++
7 files changed, 168 insertions(+), 48 deletions(-)
create mode 100644 config/example/rank_colours.txt
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index c72149c7a20..68acde69228 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -652,3 +652,22 @@
// return the split html object to the caller
return s
+
+/**
+ * Proc to generate a "rank colour" from a client
+ *
+ * This takes the client and looks at various factors in order, such as patreon status, staff rank, and more
+ * Arguments:
+ * * C - The client were looking up
+ */
+/proc/client2rankcolour(client/C)
+ // First check if end user is an admin
+ if(C.holder)
+ if(C.holder.rank in GLOB.rank_colour_map)
+ // Return their rank colour if they are in here
+ return GLOB.rank_colour_map[C.holder.rank]
+
+ // If they arent an admin, see if they are a patreon. Just accept any level
+ if(C.donator_level)
+ return "#e67e22" // Patreon orange
+ return null
diff --git a/code/_globalvars/lists/misc.dm b/code/_globalvars/lists/misc.dm
index ebdf2017900..b5fd84ef6d6 100644
--- a/code/_globalvars/lists/misc.dm
+++ b/code/_globalvars/lists/misc.dm
@@ -54,4 +54,7 @@ GLOBAL_LIST_INIT(cooking_recipes, list(RECIPE_MICROWAVE = list(), RECIPE_OVEN =
GLOBAL_LIST_INIT(cooking_ingredients, list(RECIPE_MICROWAVE = list(), RECIPE_OVEN = list(), RECIPE_GRILL = list(), RECIPE_CANDY = list()))
GLOBAL_LIST_INIT(cooking_reagents, list(RECIPE_MICROWAVE = list(), RECIPE_OVEN = list(), RECIPE_GRILL = list(), RECIPE_CANDY = list()))
+/// Associative list of admin rank to colour. Set in config/rank_colours.txt
+GLOBAL_LIST_EMPTY(rank_colour_map)
+
#define EGG_LAYING_MESSAGES list("lays an egg.", "squats down and croons.", "begins making a huge racket.", "begins clucking raucously.")
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index aa43133d111..3b39682efbf 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -925,3 +925,34 @@
runnable_modes[M] = probabilities[M.config_tag]
// to_chat(world, "DEBUG: runnable_mode\[[runnable_modes.len]\] = [M.config_tag]")
return runnable_modes
+
+/datum/configuration/proc/load_rank_colour_map()
+ var/list/lines = file2list("config/rank_colours.txt")
+
+ for(var/line in lines)
+ // Skip newlines
+ if(!length(line))
+ continue
+ // Skip comments
+ if(line[1] == "#")
+ continue
+
+ //Split the line at every " - "
+ var/list/split_holder = splittext(line, " - ")
+ if(!length(split_holder))
+ continue
+
+ // Rank is before the " - "
+ var/rank = split_holder[1]
+ if(!rank)
+ continue
+
+ // Color is after the " - "
+ var/colour = ""
+ if(length(split_holder) >= 2)
+ colour = split_holder[2]
+
+ if(rank && colour)
+ GLOB.rank_colour_map[rank] = colour
+ else
+ stack_trace("Invalid colour for rank '[rank]' in config/rank_colours.txt")
diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm
index 4a0429dd576..449ff234157 100644
--- a/code/game/verbs/who.dm
+++ b/code/game/verbs/who.dm
@@ -1,63 +1,98 @@
-
/client/verb/who()
set name = "Who"
set category = "OOC"
- var/msg = "Current Players:\n"
+ var/list/lines = list()
+ var/list/temp = list()
+ for(var/client/C in GLOB.clients)
+ if(C.holder && C.holder.big_brother) // BB doesn't show up at all
+ continue
+
+ if(C.holder && C.holder.fakekey)
+ temp += C.holder.fakekey
+ else
+ temp += C.key
+
+ temp = sortList(temp) // Sort it. We dont do this above because fake keys would be out of order, which would be a giveaway
+
+ var/list/output_players = list()
+
+ // Now go over it again to apply colours.
+ for(var/p in temp)
+ var/client/C = GLOB.directory[ckey(p)]
+ if(!C)
+ // This should NEVER happen, but better to be safe
+ continue
+ // Get the colour
+ var/colour = client2rankcolour(C)
+ var/out = "[p]"
+ if(C.holder)
+ out = "[out]"
+ if(colour)
+ out = "[out]"
+
+ output_players += out
+
+ lines += "Current Players ([length(output_players)]): "
+ lines += output_players.Join(", ") // Turn players into a comma separated list
+
+ if(check_rights(R_ADMIN, FALSE))
+ lines += "Click here for detailed (old) who."
+
+ var/msg = lines.Join("\n")
+
+ to_chat(src, msg)
+
+// Advanced version of `who` to show player age, antag status and more. Lags the chat when loading, so its in its own proc
+/client/proc/who_advanced()
+ if(!check_rights(R_ADMIN))
+ return
var/list/Lines = list()
- if(check_rights(R_ADMIN,0))
- for(var/client/C in GLOB.clients)
- if(C.holder && C.holder.big_brother && !check_rights(R_PERMISSIONS, 0)) // need PERMISSIONS to see BB
- continue
+ for(var/client/C in GLOB.clients)
+ if(C.holder && C.holder.big_brother && !check_rights(R_PERMISSIONS, FALSE)) // need PERMISSIONS to see BB
+ continue
- var/entry = "\t[C.key]"
- if(C.holder && C.holder.fakekey)
- entry += " (as [C.holder.fakekey])"
- entry += " - Playing as [C.mob.real_name]"
- switch(C.mob.stat)
- if(UNCONSCIOUS)
- entry += " - Unconscious"
- if(DEAD)
- if(isobserver(C.mob))
- var/mob/dead/observer/O = C.mob
- if(O.started_as_observer)
- entry += " - Observing"
- else
- entry += " - DEAD"
- else if(isnewplayer(C.mob))
- entry += " - New Player"
+ var/entry = "\t[C.key]"
+ if(C.holder && C.holder.fakekey)
+ entry += " (as [C.holder.fakekey])"
+ entry += " - Playing as [C.mob.real_name]"
+ switch(C.mob.stat)
+ if(UNCONSCIOUS)
+ entry += " - Unconscious"
+ if(DEAD)
+ if(isobserver(C.mob))
+ var/mob/dead/observer/O = C.mob
+ if(O.started_as_observer)
+ entry += " - Observing"
else
entry += " - DEAD"
+ else if(isnewplayer(C.mob))
+ entry += " - New Player"
+ else
+ entry += " - DEAD"
- var/age
- if(isnum(C.player_age))
- age = C.player_age
- else
- age = 0
+ var/age
+ if(isnum(C.player_age))
+ age = C.player_age
+ else
+ age = 0
- if(age <= 1)
- age = "[age]"
- else if(age < 10)
- age = "[age]"
+ if(age <= 1)
+ age = "[age]"
+ else if(age < 10)
+ age = "[age]"
- entry += " - [age]"
+ entry += " - [age]"
- if(is_special_character(C.mob))
- entry += " - Antagonist"
- entry += " ([ADMIN_QUE(C.mob,"?")])"
- Lines += entry
- else
- for(var/client/C in GLOB.clients)
- if(C.holder && C.holder.big_brother) // BB doesn't show up at all
- continue
+ if(is_special_character(C.mob))
+ entry += " - Antagonist"
+ entry += " ([ADMIN_QUE(C.mob, "?")])"
+ Lines += entry
- if(C.holder && C.holder.fakekey)
- Lines += C.holder.fakekey
- else
- Lines += C.key
+ var/msg = ""
for(var/line in sortList(Lines))
msg += "[line]\n"
@@ -83,7 +118,12 @@
if(C.holder.big_brother && !check_rights(R_PERMISSIONS, 0)) // normal admins can't see BB
continue
- msg += "\t[C] is a [C.holder.rank]"
+ // Their rank may not have a defined colour, only set colour if so
+ var/rank_colour = client2rankcolour(C)
+ if(rank_colour)
+ msg += "[C] is a [C.holder.rank]"
+ else
+ msg += "[C] is a [C.holder.rank]"
if(C.holder.fakekey)
msg += " (as [C.holder.fakekey])"
@@ -102,7 +142,12 @@
num_admins_online++
else if(check_rights(R_MENTOR|R_MOD, 0, C.mob))
- modmsg += "\t[C] is a [C.holder.rank]"
+ // Their rank may not have a defined colour, only set colour if so
+ var/rank_colour = client2rankcolour(C)
+ if(rank_colour)
+ modmsg += "[C] is a [C.holder.rank]"
+ else
+ modmsg += "[C] is a [C.holder.rank]"
if(isobserver(C.mob))
modmsg += " - Observing"
@@ -120,10 +165,18 @@
if(check_rights(R_ADMIN, 0, C.mob))
if(!C.holder.fakekey)
- msg += "\t[C] is a [C.holder.rank]\n"
+ var/rank_colour = client2rankcolour(C)
+ if(rank_colour)
+ msg += "[C] is a [C.holder.rank]"
+ else
+ msg += "[C] is a [C.holder.rank]"
num_admins_online++
else if(check_rights(R_MOD|R_MENTOR, 0, C.mob) && !check_rights(R_ADMIN, 0, C.mob))
- modmsg += "\t[C] is a [C.holder.rank]\n"
+ var/rank_colour = client2rankcolour(C)
+ if(rank_colour)
+ modmsg += "[C] is a [C.holder.rank]"
+ else
+ modmsg += "[C] is a [C.holder.rank]"
num_mods_online++
var/noadmins_info = "\nIf no admins or mentors are online, make a ticket anyways. Adminhelps and mentorhelps will be relayed to discord, and staff will still be informed."
diff --git a/code/game/world.dm b/code/game/world.dm
index 5ba97917661..b3abac365e8 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -190,6 +190,7 @@ GLOBAL_LIST_EMPTY(world_topic_handlers)
config.load("config/game_options.txt","game_options")
config.loadsql("config/dbconfig.txt")
config.loadoverflowwhitelist("config/ofwhitelist.txt")
+ config.load_rank_colour_map()
// apply some settings from config..
/world/proc/update_status()
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 26fa05cebfb..db9a440c11d 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -3556,6 +3556,8 @@
var/datum/browser/popup = new(usr, "view_karma", "Karma stats for [target_ckey]", 600, 300)
popup.set_content(dat)
popup.open(FALSE)
+ else if(href_list["who_advanced"])
+ usr.client.who_advanced()
/client/proc/create_eventmob_for(mob/living/carbon/human/H, killthem = 0)
if(!check_rights(R_EVENT))
diff --git a/config/example/rank_colours.txt b/config/example/rank_colours.txt
new file mode 100644
index 00000000000..b35641c39f4
--- /dev/null
+++ b/config/example/rank_colours.txt
@@ -0,0 +1,11 @@
+# Use this file to denote colours for ingame admin ranks, using the following format
+# Rankname - #12A5F4
+# Colours dont have to be in hex, since this colour string is thrown into the style -aa
+Head of Staff - #e74c3c
+Maintainer - #992d22
+Server Dev - #1abc9c
+Community Manager - #e91e63
+Game Admin - #238afa
+Trial Admin - #7fb6fc
+PR Reviewer - #c27c0e
+Mentor - #f1c40f