diff --git a/cfg/admin.txt b/cfg/admin.txt
index e69de29bb2..8b13789179 100644
--- a/cfg/admin.txt
+++ b/cfg/admin.txt
@@ -0,0 +1 @@
+
diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm
index ff60d1c030..1516be9fa3 100644
--- a/code/__DEFINES/citadel_defines.dm
+++ b/code/__DEFINES/citadel_defines.dm
@@ -99,3 +99,5 @@
//Brainslugs
#define isborer(A) (istype(A, /mob/living/simple_animal/borer))
+
+#define CITADEL_MENTOR_OOC_COLOUR "#ad396e"
\ No newline at end of file
diff --git a/code/__HELPERS/text_vr.dm b/code/__HELPERS/text_vr.dm
index 7cd683f456..846cb1b26a 100644
--- a/code/__HELPERS/text_vr.dm
+++ b/code/__HELPERS/text_vr.dm
@@ -17,11 +17,11 @@ proc/TextPreview(var/string,var/len=40)
else
return "[copytext(string, 1, 37)]..."
-GLOBAL_LIST_EMPTY(mentor_log)
-GLOBAL_PROTECT(mentor_log)
+GLOBAL_LIST_EMPTY(mentorlog)
+GLOBAL_PROTECT(mentorlog)
GLOBAL_LIST_EMPTY(whitelisted_species_list)
/proc/log_mentor(text)
- GLOB.mentor_log.Add(text)
- GLOB.world_game_log << "\[[time_stamp()]]MENTOR: [text]"
\ No newline at end of file
+ GLOB.mentorlog.Add(text)
+ GLOB.world_game_log << "\[[time_stamp()]]MENTOR: [text]"
\ No newline at end of file
diff --git a/code/citadel/_cit_helpers.dm b/code/citadel/_cit_helpers.dm
index 1eacc01ef3..f4772fa464 100644
--- a/code/citadel/_cit_helpers.dm
+++ b/code/citadel/_cit_helpers.dm
@@ -86,9 +86,6 @@ GLOBAL_LIST_INIT(dildo_colors, list(//mostly neon colors
"Purple" = "#e300ff"//purple
))
-//mentor stuff
-GLOBAL_LIST_EMPTY(mentors)
-
//Looc stuff
GLOBAL_VAR_INIT(looc_allowed, 1)
GLOBAL_VAR_INIT(dlooc_allowed, 1)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index fc4e04f97e..b1f0b1e09c 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -44,7 +44,10 @@
body += "
Show related accounts by: "
body += "\[ CID | "
body += "IP \]"
-
+ body += "
"
+ body += "Make mentor | "
+ body += "Remove mentor"
+ body += "
"
body += "
\[ "
body += "VV - "
diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm
index 01e37fdb1f..a758d295e2 100644
--- a/code/modules/admin/secrets.dm
+++ b/code/modules/admin/secrets.dm
@@ -107,6 +107,8 @@
dat += "No-one has done anything this round!"
usr << browse(dat, "window=admin_log")
+ if("mentor_log")
+ CitadelMentorLogSecret()
if("list_job_debug")
var/dat = "Job Debug info.
"
for(var/line in SSjob.job_debug)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 08b3abe795..a694b8816b 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -22,6 +22,8 @@
if(!CheckAdminHref(href, href_list))
return
+ citaTopic(href, href_list) // Citadel
+
if(href_list["ahelp"])
if(!check_rights(R_ADMIN, TRUE))
return
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 2c85b46603..bbb0f1ed3d 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -87,6 +87,8 @@
hsrc = holder
if("usr")
hsrc = mob
+ if("mentor") // CITADEL
+ hsrc = mentor_datum // CITADEL END
if("prefs")
if (inprefs)
return
@@ -183,6 +185,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
else if(GLOB.deadmins[ckey])
verbs += /client/proc/readmin
connecting_admin = TRUE
+ mentor_datum_set()// Citadel mentor_holder setting
//preferences datum - also holds some persistent data for the client (because we may as well keep these datums to a minimum)
prefs = GLOB.preferences_datums[ckey]
diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm
index 42b497fc09..2da25dd5df 100644
--- a/code/modules/client/verbs/ooc.dm
+++ b/code/modules/client/verbs/ooc.dm
@@ -67,6 +67,8 @@
to_chat(C, "OOC: [keyname][holder.fakekey ? "/([holder.fakekey])" : ""]: [msg]")
else
to_chat(C, "OOC: [holder.fakekey ? holder.fakekey : key]: [msg]")
+ else if(is_mentor()) // Citadel Mentors
+ to_chat(C, "OOC: [keyname]: [msg]") // hippie end
else if(!(key in C.prefs.ignoring))
to_chat(C, "OOC: [keyname]: [msg]")
diff --git a/code/modules/client/verbs/who.dm b/code/modules/client/verbs/who.dm
index a32da8ab69..8b9ea8f2e8 100644
--- a/code/modules/client/verbs/who.dm
+++ b/code/modules/client/verbs/who.dm
@@ -84,6 +84,6 @@
continue //Don't show afk admins to adminwho
if(!C.holder.fakekey)
msg += "\t[C] is a [C.holder.rank]\n"
- msg += "Adminhelps are also sent to IRC. If no admins are available in game adminhelp anyways and an admin on IRC will see it and respond."
+ msg += "Adminhelps are also sent to Discord. If no admins are available in game adminhelp anyways and an admin on Discord will see it and respond."
to_chat(src, msg)
diff --git a/code/modules/mentor/follow.dm b/code/modules/mentor/follow.dm
deleted file mode 100644
index d744fe2643..0000000000
--- a/code/modules/mentor/follow.dm
+++ /dev/null
@@ -1,50 +0,0 @@
-/client/proc/mentor_follow(var/mob/living/M)
- if(!check_mentor())
- return
-
- if(isnull(M))
- return
-
- if(!istype(usr, /mob))
- return
-
- if(!holder)
- var/datum/mentors/mentor = GLOB.mentor_datums[usr.client.ckey]
- mentor.following = M
-/* else
- holder.following = M*/
-
- usr.reset_perspective(M)
- src.verbs += /client/proc/mentor_unfollow
-
- to_chat(GLOB.admins, "MENTOR: [key_name(usr)] is now following [key_name(M)]")
- to_chat(usr, "You are now following [M]. Click the \"Stop Following\" button in the Mentor tab to stop.")
- log_mentor("[key_name(usr)] began following [key_name(M)]")
-
-
-
-/client/proc/mentor_unfollow()
- set category = "Mentor"
- set name = "Stop Following"
- set desc = "Stop following the followed."
-
- if(!check_mentor())
- return
-
- usr.reset_perspective(null)
- src.verbs -= /client/proc/mentor_unfollow
-
- var/following = null
- if(!holder)
- var/datum/mentors/mentor = GLOB.mentor_datums[usr.client.ckey]
- following = mentor.following
- /*else
- following = holder.following*/
-
-
- to_chat(GLOB.admins, "MENTOR: [key_name(usr)] is no longer following [key_name(following)]")
- to_chat(usr, "You are no longer following [following].")
- log_mentor("[key_name(usr)] stopped following [key_name(following)]")
-
- following = null
-
diff --git a/code/modules/mentor/holder2.dm b/code/modules/mentor/holder2.dm
deleted file mode 100644
index 8cd6609505..0000000000
--- a/code/modules/mentor/holder2.dm
+++ /dev/null
@@ -1,46 +0,0 @@
-GLOBAL_LIST(mentor_datums)
-
-/datum/mentors
- var/client/owner = null
- var/following = null
-
-/datum/mentors/New(ckey)
- if(!ckey)
- del(src)
- return
- GLOB.mentor_datums[ckey] = src
-
-/datum/mentors/proc/associate(client/C)
- if(istype(C))
- owner = C
- GLOB.mentors |= C
-
-/datum/mentors/proc/disassociate()
- if(owner)
- GLOB.mentors -= owner
- owner = null
-
-/client/proc/dementor()
- var/mentor = GLOB.mentor_datums[ckey]
- GLOB.mentor_datums -= ckey
- qdel(mentor)
-
- return 1
-
-/proc/check_mentor()
- if(usr && usr.client)
- var/mentor = GLOB.mentor_datums[usr.client.ckey]
- if(mentor || check_rights(R_ADMIN,0))
- return 1
-
- return 0
-
-/proc/check_mentor_other(var/client/C)
- if(C)
- var/mentor = GLOB.mentor_datums[C.ckey]
- if(C.holder && C.holder.rank)
- if(C.holder.rank.rights & R_ADMIN)
- return 1
- else if(mentor)
- return 1
- return 0
\ No newline at end of file
diff --git a/code/modules/mentor/mentor_ranks.dm b/code/modules/mentor/mentor_ranks.dm
deleted file mode 100644
index 1e132680d4..0000000000
--- a/code/modules/mentor/mentor_ranks.dm
+++ /dev/null
@@ -1,43 +0,0 @@
-/proc/load_mentors()
- //clear the datums references
- GLOB.mentor_datums.Cut()
- GLOB.mentors.Cut()
-
- if(!config.mentor_legacy_system)
- if(!GLOB.dbcon.IsConnected())
- world.log << "Failed to connect to database in load_mentors()."
- GLOB.diary << "Failed to connect to database in load_mentors()."
- config.mentor_legacy_system = 1
- load_mentors()
- return
-
- var/DBQuery/query = GLOB.dbcon.NewQuery("SELECT ckey FROM [format_table_name("mentor")]")
- query.Execute()
- while(query.NextRow())
- var/ckey = ckey(query.item[1])
- var/datum/mentors/D = new(ckey) //create the mentor datum and store it for later use
- if(!D) continue //will occur if an invalid rank is provided
- D.associate(GLOB.directory[ckey]) //find the client for a ckey if they are connected and associate them with the new mentor datum
- else
- world.log << "Using legacy mentor system."
- var/list/Lines = file2list("config/mentors.txt")
-
- //process each line seperately
- for(var/line in Lines)
- if(!length(line)) continue
- if(findtextEx(line,"#",1,2)) continue
-
- //ckey is before the first "="
- var/ckey = ckey(line)
- if(!ckey) continue
-
- var/datum/mentors/D = new(ckey) //create the admin datum and store it for later use
- if(!D) continue //will occur if an invalid rank is provided
- D.associate(GLOB.directory[ckey]) //find the client for a ckey if they are connected and associate them with the new admin datum
-
- #ifdef TESTING
- var/msg = "mentors Built:\n"
- for(var/ckey in GLOB.mentor_datums)
- msg += "\t[ckey] - mentor\n"
- testing(msg)
- #endif
\ No newline at end of file
diff --git a/config/config.txt b/config/config.txt
index e63dc34bb0..0440549c88 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -35,6 +35,14 @@ ROUND_END_COUNTDOWN 90
## This flag is automatically enabled if SQL_ENABLED isn't
ADMIN_LEGACY_SYSTEM
+## Comment this out if you want to use the SQL based mentor system, the legacy system uses mentors.txt.
+## You need to set up your database to use the SQL based system.
+## This flag is automatically enabled if SQL_ENABLED isn't
+MENTOR_LEGACY_SYSTEM
+
+#Mentors only see ckeys by default. Uncomment to have them only see mob name
+#MENTORS_MOBNAME_ONLY
+
## Comment this out if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system.
BAN_LEGACY_SYSTEM
diff --git a/modular_citadel/code/_globalvars/lists/mobs.dm b/modular_citadel/code/_globalvars/lists/mobs.dm
new file mode 100644
index 0000000000..5317685d00
--- /dev/null
+++ b/modular_citadel/code/_globalvars/lists/mobs.dm
@@ -0,0 +1,2 @@
+GLOBAL_LIST_EMPTY(mentors) //all clients whom are admins
+GLOBAL_PROTECT(mentors)
\ No newline at end of file
diff --git a/modular_citadel/code/controllers/configuration/entries/general.dm b/modular_citadel/code/controllers/configuration/entries/general.dm
new file mode 100644
index 0000000000..94acd4c48e
--- /dev/null
+++ b/modular_citadel/code/controllers/configuration/entries/general.dm
@@ -0,0 +1,4 @@
+/datum/config_entry/flag/mentors_mobname_only
+
+/datum/config_entry/flag/mentor_legacy_system //Defines whether the server uses the legacy mentor system with mentors.txt or the SQL system
+ protection = CONFIG_ENTRY_LOCKED
\ No newline at end of file
diff --git a/modular_citadel/code/init.dm b/modular_citadel/code/init.dm
index 416c3f07c4..8432df7ac3 100644
--- a/modular_citadel/code/init.dm
+++ b/modular_citadel/code/init.dm
@@ -1,4 +1,26 @@
//init file stolen from hippie
/proc/cit_initialize()
- initialize_global_loadout_items()
\ No newline at end of file
+ load_mentors()
+ initialize_global_loadout_items()
+
+ //body parts and things
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails, GLOB.mam_tails_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_ears, GLOB.mam_ears_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_tails_animated, GLOB.mam_tails_animated_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/taur, GLOB.taur_list)
+// init_sprite_accessory_subtypes(/datum/sprite_accessory/beaks/avian, GLOB.avian_beaks_list)
+// init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/avian, GLOB.avian_tails_list)
+// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_wings, GLOB.avian_wings_list)
+// init_sprite_accessory_subtypes(/datum/sprite_accessory/avian_open_wings, GLOB.avian_open_wings_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_head, GLOB.xeno_head_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_tail, GLOB.xeno_tail_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_dorsal, GLOB.xeno_dorsal_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list)
+ for(var/K in GLOB.cock_shapes_list)
+ var/datum/sprite_accessory/penis/value = GLOB.cock_shapes_list[K]
+ GLOB.cock_shapes_icons[K] = value.icon_state
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list)
+ init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list)
+ GLOB.breasts_size_list = list("a","b","c","d","e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing.
\ No newline at end of file
diff --git a/modular_citadel/code/modules/admin/admin.dm b/modular_citadel/code/modules/admin/admin.dm
new file mode 100644
index 0000000000..8e3bc66a22
--- /dev/null
+++ b/modular_citadel/code/modules/admin/admin.dm
@@ -0,0 +1,6 @@
+/client/proc/citaPPoptions(mob/M) // why is this client and not /datum/admins? noone knows, in PP src == client, instead of holder. wtf.
+ var/body = "
"
+ if(M.client)
+ body += "Make mentor | "
+ body += "Remove mentor"
+ return body
\ No newline at end of file
diff --git a/modular_citadel/code/modules/admin/holder2.dm b/modular_citadel/code/modules/admin/holder2.dm
new file mode 100644
index 0000000000..f581de8dfc
--- /dev/null
+++ b/modular_citadel/code/modules/admin/holder2.dm
@@ -0,0 +1,14 @@
+/datum/admins
+ var/following = null
+
+/datum/admins/associate(client/C)
+ removeMentor(C.ckey) //safety to avoid multiple datums and other weird shit i cannot comprehend
+ ..()
+ if(istype(C))
+ C.mentor_datum_set(TRUE)
+
+/datum/admins/disassociate()
+ if(owner)
+ owner.remove_mentor_verbs()
+ owner.mentor_datum = null
+ ..()
\ No newline at end of file
diff --git a/modular_citadel/code/modules/admin/secrets.dm b/modular_citadel/code/modules/admin/secrets.dm
new file mode 100644
index 0000000000..9fbc8501dd
--- /dev/null
+++ b/modular_citadel/code/modules/admin/secrets.dm
@@ -0,0 +1,8 @@
+/datum/admins/proc/CitadelMentorLogSecret()
+ var/dat = "Mentor Log
"
+ for(var/l in GLOB.mentorlog)
+ dat += "[l]"
+
+ if(!GLOB.mentorlog.len)
+ dat += "No mentors have done anything this round!"
+ usr << browse(dat, "window=mentor_log")
\ No newline at end of file
diff --git a/modular_citadel/code/modules/admin/topic.dm b/modular_citadel/code/modules/admin/topic.dm
new file mode 100644
index 0000000000..bdd8758882
--- /dev/null
+++ b/modular_citadel/code/modules/admin/topic.dm
@@ -0,0 +1,55 @@
+/datum/admins/proc/citaTopic(href, href_list)
+
+/datum/admins/proc/makeMentor(ckey)
+ if(!usr.client)
+ return
+ if (!check_rights(0))
+ return
+ if(!ckey)
+ return
+ var/client/C = GLOB.directory[ckey]
+ if(C)
+ if(check_rights_for(C, R_ADMIN,0))
+ to_chat(usr, "The client chosen is an admin! Cannot mentorize.")
+ return
+ if(SSdbcore.Connect())
+ var/datum/DBQuery/query_get_mentor = SSdbcore.NewQuery("SELECT id FROM [format_table_name("mentor")] WHERE ckey = '[ckey]'")
+ if(query_get_mentor.NextRow())
+ to_chat(usr, "[ckey] is already a mentor.")
+ return
+ var/datum/DBQuery/query_add_mentor = SSdbcore.NewQuery("INSERT INTO `[format_table_name("mentor")]` (`id`, `ckey`) VALUES (null, '[ckey]')")
+ if(!query_add_mentor.warn_execute())
+ return
+ var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new mentor [ckey]');")
+ if(!query_add_admin_log.warn_execute())
+ return
+ else
+ to_chat(usr, "Failed to establish database connection. The changes will last only for the current round.")
+ new /datum/mentors(ckey)
+ to_chat(usr, "New mentor added.")
+
+/datum/admins/proc/removeMentor(ckey)
+ if(!usr.client)
+ return
+ if (!check_rights(0))
+ return
+ if(!ckey)
+ return
+ var/client/C = GLOB.directory[ckey]
+ if(C)
+ if(check_rights_for(C, R_ADMIN,0))
+ to_chat(usr, "The client chosen is an admin, not a mentor! Cannot de-mentorize.")
+ return
+ C.remove_mentor_verbs()
+ C.mentor_datum = null
+ GLOB.mentors -= C
+ if(SSdbcore.Connect())
+ var/datum/DBQuery/query_remove_mentor = SSdbcore.NewQuery("DELETE FROM [format_table_name("mentor")] WHERE ckey = '[ckey]'")
+ if(!query_remove_mentor.warn_execute())
+ return
+ var/datum/DBQuery/query_add_admin_log = SSdbcore.NewQuery("INSERT INTO `[format_table_name("admin_log")]` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed mentor [ckey]');")
+ if(!query_add_admin_log.warn_execute())
+ return
+ else
+ to_chat(usr, "Failed to establish database connection. The changes will last only for the current round.")
+ to_chat(usr, "Mentor removed.")
\ No newline at end of file
diff --git a/modular_citadel/code/modules/client/client_procs.dm b/modular_citadel/code/modules/client/client_procs.dm
new file mode 100644
index 0000000000..5bb53ee0f2
--- /dev/null
+++ b/modular_citadel/code/modules/client/client_procs.dm
@@ -0,0 +1,14 @@
+/client/proc/mentor_datum_set(admin)
+ mentor_datum = GLOB.mentor_datums[ckey]
+ if(!mentor_datum && check_rights_for(src, R_ADMIN,0)) // admin with no mentor datum?let's fix that
+ new /datum/mentors(ckey)
+ if(mentor_datum)
+ if(!check_rights_for(src, R_ADMIN,0) && !admin)
+ GLOB.mentors |= src // don't add admins to this list too.
+ mentor_datum.owner = src
+ add_mentor_verbs()
+ mentor_memo_output("Show")
+
+/client/proc/is_mentor() // admins are mentors too.
+ if(mentor_datum || check_rights_for(src, R_ADMIN,0))
+ return TRUE
diff --git a/modular_citadel/code/modules/client/verbs/who.dm b/modular_citadel/code/modules/client/verbs/who.dm
new file mode 100644
index 0000000000..091dd7bf79
--- /dev/null
+++ b/modular_citadel/code/modules/client/verbs/who.dm
@@ -0,0 +1,125 @@
+/client/verb/mentorwho()
+ set category = "Mentor"
+ set name = "Mentorwho"
+ var/msg = "Current Mentors:\n"
+ for(var/X in GLOB.mentors)
+ var/client/C = X
+ if(!C)
+ GLOB.mentors -= C
+ continue // weird runtime that happens randomly
+ var/suffix = ""
+ if(holder)
+ if(isobserver(C.mob))
+ suffix += " - Observing"
+ else if(istype(C.mob,/mob/dead/new_player))
+ suffix += " - Lobby"
+ else
+ suffix += " - Playing"
+
+ if(C.is_afk())
+ suffix += " (AFK)"
+ msg += "\t[C][suffix]\n"
+ to_chat(src, msg)
+
+/client/verb/who()
+ set name = "Who"
+ set category = "OOC"
+
+ var/msg = ""
+
+ var/list/Lines = list()
+ if(length(GLOB.admins))
+ Lines += "Admins:"
+ for(var/X in GLOB.admins)
+ var/client/C = X
+ if(C && C.holder && !C.holder.fakekey)
+ Lines += "\t [C.key][show_admin_info(C)] ([round(C.avgping, 1)]ms)"
+ if(length(GLOB.mentors))
+ Lines += "Mentors:"
+ for(var/X in GLOB.mentors)
+ var/client/C = X
+ if(C)
+ Lines += "\t [C.key][show_admin_info(C)] ([round(C.avgping, 1)]ms)"
+
+ Lines += "Players:"
+ for(var/X in sortList(GLOB.clients))
+ var/client/C = X
+ if(!C) continue
+ var/key = C.key
+ if(C.holder && C.holder.fakekey)
+ key = C.holder.fakekey
+ Lines += "\t [key][show_admin_info(C)] ([round(C.avgping, 1)]ms)"
+
+ for(var/line in Lines)
+ msg += "[line]\n"
+
+ msg += "Total Players: [length(GLOB.clients)]"
+ to_chat(src, msg)
+
+/client/proc/show_admin_info(var/client/C)
+ if(!C)
+ return ""
+
+ if(!check_rights_for(src, R_ADMIN))
+ return ""
+
+ var/entry = ""
+ if(C.holder && C.holder.fakekey)
+ entry += " (as [C.holder.fakekey])"
+ if (isnewplayer(C.mob))
+ entry += " - In Lobby"
+ else
+ 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
+ entry += " - DEAD"
+ if(is_special_character(C.mob))
+ entry += " - Antagonist"
+ entry += " (?)"
+ return entry
+
+/client/verb/adminwho()
+ set category = "Admin"
+ set name = "Adminwho"
+
+ var/msg = "Current Admins:\n"
+ if(check_rights_for(src, R_ADMIN))
+ for(var/X in GLOB.admins)
+ var/client/C = X
+ if(!check_rights_for(C, R_ADMIN))
+ continue
+ msg += "\t[C] is a [C.holder.rank]"
+
+ if(C.holder.fakekey)
+ msg += " (as [C.holder.fakekey])"
+
+ if(isobserver(C.mob))
+ msg += " - Observing"
+ else if(isnewplayer(C.mob))
+ msg += " - Lobby"
+ else
+ msg += " - Playing"
+
+ if(C.is_afk())
+ msg += " (AFK)"
+ msg += "\n"
+ else
+ for(var/X in GLOB.admins)
+ var/client/C = X
+ if(!check_rights_for(C, R_ADMIN))
+ continue
+ if(C.is_afk())
+ continue //Don't show afk admins to adminwho
+ if(!C.holder.fakekey)
+ msg += "\t[C] is a [C.holder.rank]\n"
+ msg += "Adminhelps are also sent to Discord. If no admins are available in game adminhelp anyways and an admin on Discord will see it and respond."
+ to_chat(src, msg)
diff --git a/modular_citadel/code/modules/mentor/follow.dm b/modular_citadel/code/modules/mentor/follow.dm
new file mode 100644
index 0000000000..7c53c5c0fb
--- /dev/null
+++ b/modular_citadel/code/modules/mentor/follow.dm
@@ -0,0 +1,26 @@
+/client/proc/mentor_follow(mob/living/M)
+ if(!is_mentor())
+ return
+ if(isnull(M))
+ return
+ if(!ismob(usr))
+ return
+ mentor_datum.following = M
+ usr.reset_perspective(M)
+ verbs += /client/proc/mentor_unfollow
+ to_chat(GLOB.admins, "MENTOR: [key_name(usr)] is now following [key_name(M)]")
+ to_chat(usr, "Click the \"Stop Following\" button in the Mentor tab to stop following [key_name(M)].")
+ log_mentor("[key_name(usr)] began following [key_name(M)]")
+
+/client/proc/mentor_unfollow()
+ set category = "Mentor"
+ set name = "Stop Following"
+ set desc = "Stop following the followed."
+
+ if(!is_mentor())
+ return
+ usr.reset_perspective()
+ verbs -= /client/proc/mentor_unfollow
+ to_chat(GLOB.admins, "MENTOR: [key_name(usr)] is no longer following [key_name(mentor_datum.following)]")
+ log_mentor("[key_name(usr)] stopped following [key_name(mentor_datum.following)]")
+ mentor_datum.following = null
diff --git a/modular_citadel/code/modules/mentor/mentor.dm b/modular_citadel/code/modules/mentor/mentor.dm
new file mode 100644
index 0000000000..e0cdf565b6
--- /dev/null
+++ b/modular_citadel/code/modules/mentor/mentor.dm
@@ -0,0 +1,113 @@
+GLOBAL_LIST_EMPTY(mentor_datums)
+GLOBAL_PROTECT(mentor_datums)
+
+GLOBAL_VAR_INIT(mentor_href_token, GenerateToken())
+GLOBAL_PROTECT(mentor_href_token)
+
+/datum/mentors
+ var/name = "someone's mentor datum"
+ var/client/owner // the actual mentor, client type
+ var/target // the mentor's ckey
+ var/href_token // href token for mentor commands, uses the same token used by admins.
+ var/mob/following
+
+/datum/mentors/New(ckey)
+ if(!ckey)
+ QDEL_IN(src, 0)
+ throw EXCEPTION("Mentor datum created without a ckey")
+ return
+ target = ckey(ckey)
+ name = "[ckey]'s mentor datum"
+ href_token = GenerateToken()
+ GLOB.mentor_datums[target] = src
+ //set the owner var and load commands
+ owner = GLOB.directory[ckey]
+ if(owner)
+ owner.mentor_datum = src
+ owner.add_mentor_verbs()
+ if(!check_rights_for(owner, R_ADMIN,0)) // don't add admins to mentor list.
+ GLOB.mentors += owner
+
+/datum/mentors/proc/CheckMentorHREF(href, href_list)
+ var/auth = href_list["mentor_token"]
+ . = auth && (auth == href_token || auth == GLOB.mentor_href_token)
+ if(.)
+ return
+ var/msg = !auth ? "no" : "a bad"
+ message_admins("[key_name_admin(usr)] clicked an href with [msg] authorization key!")
+ if(CONFIG_GET(flag/debug_admin_hrefs))
+ message_admins("Debug mode enabled, call not blocked. Please ask your coders to review this round's logs.")
+ log_world("UAH: [href]")
+ return TRUE
+ log_admin_private("[key_name(usr)] clicked an href with [msg] authorization key! [href]")
+
+/proc/RawMentorHrefToken(forceGlobal = FALSE)
+ var/tok = GLOB.mentor_href_token
+ if(!forceGlobal && usr)
+ var/client/C = usr.client
+ to_chat(world, C)
+ to_chat(world, usr)
+ if(!C)
+ CRASH("No client for HrefToken()!")
+ var/datum/mentors/holder = C.mentor_datum
+ if(holder)
+ tok = holder.href_token
+ return tok
+
+/proc/MentorHrefToken(forceGlobal = FALSE)
+ return "mentor_token=[RawMentorHrefToken(forceGlobal)]"
+
+/datum/mentors/Topic(href, href_list)
+ ..()
+ if(!usr || !usr.client || usr.client != owner || !usr.client.is_mentor())
+ return
+ if(!CheckMentorHREF(href, href_list))
+ return
+ if(href_list["mentor_msg"])
+ if(CONFIG_GET(flag/mentors_mobname_only))
+ var/mob/M = locate(href_list["mentor_msg"])
+ usr.client.cmd_mentor_pm(M,null)
+ else
+ usr.client.cmd_mentor_pm(href_list["mentor_msg"],null)
+ return
+
+ //Mentor Follow
+ if(href_list["mentor_follow"])
+ var/mob/living/M = locate(href_list["mentor_follow"])
+
+ if(istype(M))
+ usr.client.mentor_follow(M)
+
+ return
+
+/proc/load_mentors()
+ GLOB.mentor_datums.Cut()
+ for(var/client/C in GLOB.mentors)
+ C.remove_mentor_verbs()
+ C.mentor_datum = null
+ GLOB.mentors.Cut()
+ if(CONFIG_GET(flag/mentor_legacy_system))//legacy
+ var/list/lines = world.file2list("config/mentors.txt")
+ for(var/line in lines)
+ if(!length(line))
+ continue
+ if(findtextEx(line, "#", 1, 2))
+ continue
+ new /datum/mentors(line)
+ else//Database
+ if(!SSdbcore.Connect())
+ log_world("Failed to connect to database in load_mentors(). Reverting to legacy system.")
+ WRITE_FILE(GLOB.world_game_log, "Failed to connect to database in load_mentors(). Reverting to legacy system.")
+ CONFIG_SET(flag/mentor_legacy_system, TRUE)
+ load_mentors()
+ return
+ var/datum/DBQuery/query_load_mentors = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("mentor")]")
+ if(!query_load_mentors.Execute())
+ return
+ while(query_load_mentors.NextRow())
+ var/ckey = ckey(query_load_mentors.item[1])
+ new /datum/mentors(ckey)
+
+// new client var: mentor_datum. Acts the same way holder does towards admin: it holds the mentor datum. if set, the guy's a mentor.
+/client
+ var/datum/mentors/mentor_datum
\ No newline at end of file
diff --git a/code/modules/mentor/verbs/mentor_memo.dm b/modular_citadel/code/modules/mentor/mentor_memo.dm
similarity index 78%
rename from code/modules/mentor/verbs/mentor_memo.dm
rename to modular_citadel/code/modules/mentor/mentor_memo.dm
index 08302f7e7e..b9f6833e32 100644
--- a/code/modules/mentor/verbs/mentor_memo.dm
+++ b/modular_citadel/code/modules/mentor/mentor_memo.dm
@@ -1,8 +1,9 @@
/client/proc/mentor_memo()
set name = "Mentor Memos"
set category = "Server"
- if(!check_rights(0)) return
- if(!GLOB.dbcon.IsConnected())
+ if(!check_rights(0))
+ return
+ if(!SSdbcore.IsConnected())
to_chat(src, "Failed to establish database connection.")
return
var/memotask = input(usr,"Choose task.","Memo") in list("Show","Write","Edit","Remove")
@@ -13,8 +14,9 @@
/client/proc/show_mentor_memo()
set name = "Show Memos"
set category = "Mentor"
- if(!check_mentor()) return
- if(!GLOB.dbcon.IsConnected())
+ if(!is_mentor())
+ return
+ if(!SSdbcore.IsConnected())
to_chat(src, "Failed to establish database connection.")
return
mentor_memo_output("Show")
@@ -22,13 +24,13 @@
/client/proc/mentor_memo_output(task)
if(!task)
return
- if(!GLOB.dbcon.IsConnected())
+ if(!SSdbcore.IsConnected())
to_chat(src, "Failed to establish database connection.")
return
- var/sql_ckey = sanitizeSQL(src.ckey)
+ var/sql_ckey = sanitizeSQL(ckey)
switch(task)
if("Write")
- var/DBQuery/query_memocheck = GLOB.dbcon.NewQuery("SELECT ckey FROM [format_table_name("mentor_memo")] WHERE ckey = '[sql_ckey]'")
+ var/datum/DBQuery/query_memocheck = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("mentor_memo")] WHERE ckey = '[sql_ckey]'")
if(!query_memocheck.Execute())
var/err = query_memocheck.ErrorMsg()
log_game("SQL ERROR obtaining ckey from memo table. Error : \[[err]\]\n")
@@ -41,7 +43,7 @@
return
memotext = sanitizeSQL(memotext)
var/timestamp = SQLtime()
- var/DBQuery/query_memoadd = GLOB.dbcon.NewQuery("INSERT INTO [format_table_name("mentor_memo")] (ckey, memotext, timestamp) VALUES ('[sql_ckey]', '[memotext]', '[timestamp]')")
+ var/datum/DBQuery/query_memoadd = SSdbcore.NewQuery("INSERT INTO [format_table_name("mentor_memo")] (ckey, memotext, timestamp) VALUES ('[sql_ckey]', '[memotext]', '[timestamp]')")
if(!query_memoadd.Execute())
var/err = query_memoadd.ErrorMsg()
log_game("SQL ERROR adding new memo. Error : \[[err]\]\n")
@@ -49,7 +51,7 @@
log_admin("[key_name(src)] has set a mentor memo: [memotext]")
message_admins("[key_name_admin(src)] has set a mentor memo:
[memotext]")
if("Edit")
- var/DBQuery/query_memolist = GLOB.dbcon.NewQuery("SELECT ckey FROM [format_table_name("mentor_memo")]")
+ var/datum/DBQuery/query_memolist = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("mentor_memo")]")
if(!query_memolist.Execute())
var/err = query_memolist.ErrorMsg()
log_game("SQL ERROR obtaining ckey from memo table. Error : \[[err]\]\n")
@@ -65,7 +67,7 @@
if(!target_ckey)
return
var/target_sql_ckey = sanitizeSQL(target_ckey)
- var/DBQuery/query_memofind = GLOB.dbcon.NewQuery("SELECT memotext FROM [format_table_name("mentor_memo")] WHERE ckey = '[target_sql_ckey]'")
+ var/datum/DBQuery/query_memofind = SSdbcore.NewQuery("SELECT memotext FROM [format_table_name("mentor_memo")] WHERE ckey = '[target_sql_ckey]'")
if(!query_memofind.Execute())
var/err = query_memofind.ErrorMsg()
log_game("SQL ERROR obtaining memotext from memo table. Error : \[[err]\]\n")
@@ -78,7 +80,7 @@
new_memo = sanitizeSQL(new_memo)
var/edit_text = "Edited by [sql_ckey] on [SQLtime()] from
[old_memo]
to
[new_memo]
"
edit_text = sanitizeSQL(edit_text)
- var/DBQuery/update_query = GLOB.dbcon.NewQuery("UPDATE [format_table_name("mentor_memo")] SET memotext = '[new_memo]', last_editor = '[sql_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE ckey = '[target_sql_ckey]'")
+ var/datum/DBQuery/update_query = SSdbcore.NewQuery("UPDATE [format_table_name("mentor_memo")] SET memotext = '[new_memo]', last_editor = '[sql_ckey]', edits = CONCAT(IFNULL(edits,''),'[edit_text]') WHERE ckey = '[target_sql_ckey]'")
if(!update_query.Execute())
var/err = update_query.ErrorMsg()
log_game("SQL ERROR editing memo. Error : \[[err]\]\n")
@@ -90,7 +92,7 @@
log_admin("[key_name(src)] has edited [target_sql_ckey]'s mentor memo from [old_memo] to [new_memo]")
message_admins("[key_name_admin(src)] has edited [target_sql_ckey]'s mentor memo from
[old_memo]
to
[new_memo]")
if("Show")
- var/DBQuery/query_memoshow = GLOB.dbcon.NewQuery("SELECT ckey, memotext, timestamp, last_editor FROM [format_table_name("mentor_memo")]")
+ var/datum/DBQuery/query_memoshow = SSdbcore.NewQuery("SELECT ckey, memotext, timestamp, last_editor FROM [format_table_name("mentor_memo")]")
if(!query_memoshow.Execute())
var/err = query_memoshow.ErrorMsg()
log_game("SQL ERROR obtaining ckey, memotext, timestamp, last_editor from memo table. Error : \[[err]\]\n")
@@ -110,7 +112,7 @@
return
to_chat(src, output)
if("Remove")
- var/DBQuery/query_memodellist = GLOB.dbcon.NewQuery("SELECT ckey FROM [format_table_name("mentor_memo")]")
+ var/datum/DBQuery/query_memodellist = SSdbcore.NewQuery("SELECT ckey FROM [format_table_name("mentor_memo")]")
if(!query_memodellist.Execute())
var/err = query_memodellist.ErrorMsg()
log_game("SQL ERROR obtaining ckey from memo table. Error : \[[err]\]\n")
@@ -126,7 +128,7 @@
if(!target_ckey)
return
var/target_sql_ckey = sanitizeSQL(target_ckey)
- var/DBQuery/query_memodel = GLOB.dbcon.NewQuery("DELETE FROM [format_table_name("memo")] WHERE ckey = '[target_sql_ckey]'")
+ var/datum/DBQuery/query_memodel = SSdbcore.NewQuery("DELETE FROM [format_table_name("memo")] WHERE ckey = '[target_sql_ckey]'")
if(!query_memodel.Execute())
var/err = query_memodel.ErrorMsg()
log_game("SQL ERROR removing memo. Error : \[[err]\]\n")
diff --git a/modular_citadel/code/modules/mentor/mentor_verbs.dm b/modular_citadel/code/modules/mentor/mentor_verbs.dm
new file mode 100644
index 0000000000..ae23cbf5d6
--- /dev/null
+++ b/modular_citadel/code/modules/mentor/mentor_verbs.dm
@@ -0,0 +1,12 @@
+GLOBAL_PROTECT(mentor_verbs)
+GLOBAL_LIST_INIT(mentor_verbs, list(
+ /client/proc/cmd_mentor_say,
+ /client/proc/show_mentor_memo
+ ))
+
+/client/proc/add_mentor_verbs()
+ if(mentor_datum)
+ verbs += GLOB.mentor_verbs
+
+/client/proc/remove_mentor_verbs()
+ verbs -= GLOB.mentor_verbs
diff --git a/code/modules/mentor/verbs/mentorhelp.dm b/modular_citadel/code/modules/mentor/mentorhelp.dm
similarity index 65%
rename from code/modules/mentor/verbs/mentorhelp.dm
rename to modular_citadel/code/modules/mentor/mentorhelp.dm
index bb66eed19d..87b05a3f26 100644
--- a/code/modules/mentor/verbs/mentorhelp.dm
+++ b/modular_citadel/code/modules/mentor/mentorhelp.dm
@@ -1,39 +1,36 @@
/client/verb/mentorhelp(msg as text)
set category = "Mentor"
- set name = "mentorhelp"
-
- //remove out adminhelp verb temporarily to prevent spamming of mentors.
- src.verbs -= /client/verb/mentorhelp
- spawn(300)
- src.verbs += /client/verb/mentorhelp // 30 second cool-down for mentorhelp
+ set name = "Mentorhelp"
//clean the input msg
if(!msg) return
+
+ //remove out mentorhelp verb temporarily to prevent spamming of mentors.
+ verbs -= /client/verb/mentorhelp
+ spawn(300)
+ verbs += /client/verb/mentorhelp // 30 second cool-down for mentorhelp
+
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
if(!msg) return
if(!mob) return //this doesn't happen
- var/show_char = config.mentors_mobname_only
- var/mentor_msg = "MENTORHELP: [key_name_mentor(src, 1, 0, 0, show_char)]: [msg]"
- var/admin_msg = "MENTORHELP: [ADMIN_FULLMONTY(src.mob)]: [msg]"
+ var/show_char = CONFIG_GET(flag/mentors_mobname_only)
+ var/mentor_msg = "MENTORHELP: [key_name_mentor(src, 1, 0, 1, show_char)]: [msg]"
log_mentor("MENTORHELP: [key_name_mentor(src, 0, 0, 0, 0)]: [msg]")
- for(var/client/X in GLOB.mentors)
- to_chat(X, 'sound/items/bikehorn.ogg')
+ for(var/client/X in GLOB.mentors | GLOB.admins)
+ X << 'sound/items/bikehorn.ogg'
to_chat(X, mentor_msg)
- for(var/client/A in GLOB.admins)
- to_chat(A, 'sound/items/bikehorn.ogg')
- to_chat(A, admin_msg)
-
to_chat(src, "PM to-Mentors: [msg]")
return
/proc/get_mentor_counts()
. = list("total" = 0, "afk" = 0, "present" = 0)
- for(var/client/X in GLOB.mentors)
+ for(var/X in GLOB.mentors)
+ var/client/C = X
.["total"]++
- if(X.is_afk())
+ if(C.is_afk())
.["afk"]++
else
.["present"]++
@@ -71,14 +68,14 @@
if(key)
if(include_link)
- if(config.mentors_mobname_only)
- . += ""
+ if(CONFIG_GET(flag/mentors_mobname_only))
+ . += ""
else
- . += ""
+ . += ""
if(C && C.holder && C.holder.fakekey)
. += "Administrator"
- else if (char_name_only && config.mentors_mobname_only)
+ else if (char_name_only && CONFIG_GET(flag/mentors_mobname_only))
if(istype(C.mob,/mob/dead/new_player) || istype(C.mob, /mob/dead/observer)) //If they're in the lobby or observing, display their ckey
. += key
else if(C && C.mob) //If they're playing/in the round, only show the mob name
@@ -96,6 +93,6 @@
. += "*no key*"
if(include_follow)
- . += " (F)"
+ . += " (F)"
return .
\ No newline at end of file
diff --git a/code/modules/mentor/verbs/mentorpm.dm b/modular_citadel/code/modules/mentor/mentorpm.dm
similarity index 67%
rename from code/modules/mentor/verbs/mentorpm.dm
rename to modular_citadel/code/modules/mentor/mentorpm.dm
index 9a441d022f..881933d5d6 100644
--- a/code/modules/mentor/verbs/mentorpm.dm
+++ b/modular_citadel/code/modules/mentor/mentorpm.dm
@@ -2,8 +2,8 @@
/client/proc/cmd_mentor_pm_panel()
set category = "Mentor"
set name = "Mentor PM"
- if(!holder)
- to_chat(src, "Error: Mentor-PM-Panel: Only Mentors may use this command.")
+ if(!is_mentor())
+ to_chat(src, "Error: Mentor-PM-Panel: Only Mentors and Admins may use this command.")
return
var/list/client/targets[0]
for(var/client/T)
@@ -12,7 +12,7 @@
var/list/sorted = sortList(targets)
var/target = input(src,"To whom shall we send a message?","Mentor PM",null) in sorted|null
cmd_mentor_pm(targets[target],null)
- feedback_add_details("Mentor_verb","APM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+ SSblackbox.record_feedback("tally", "Mentor_verb", 1, "APM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
//takes input from cmd_mentor_pm_context, cmd_Mentor_pm_panel or /client/Topic and sends them a PM.
@@ -27,8 +27,8 @@
else if(istype(whom,/client))
C = whom
if(!C)
- if(holder) to_chat(src, "Error: Mentor-PM: Client not found.")
- else mentorhelp(msg) //Mentor we are replying to left. Mentorhelp instead
+ if(is_mentor()) to_chat(src, "Error: Mentor-PM: Client not found.")
+ else mentorhelp(msg) //Mentor we are replying to left. Mentorhelp instead(check below)
return
//get message text, limit it's length.and clean/escape html
@@ -37,8 +37,8 @@
if(!msg) return
if(!C)
- if(holder) to_chat(src, "Error: Mentor-PM: Client not found.")
- else mentorhelp(msg) //Mentor we are replying to has vanished, Mentorhelp instead
+ if(is_mentor()) to_chat(src, "Error: Mentor-PM: Client not found.")
+ else mentorhelp(msg) //Mentor we are replying to has vanished, Mentorhelp instead (how the fuck does this work?let's hope it works,shrug)
return
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
@@ -48,9 +48,9 @@
msg = emoji_parse(msg)
C << 'sound/items/bikehorn.ogg'
- var/show_char = config.mentors_mobname_only
- if(check_mentor_other(C))
- if(check_mentor()) //both are mentors
+ var/show_char = CONFIG_GET(flag/mentors_mobname_only)
+ if(C.is_mentor())
+ if(is_mentor())//both are mentors
to_chat(C, "Mentor PM from-[key_name_mentor(src, C, 1, 0, 0)]: [msg]")
to_chat(src, "Mentor PM to-[key_name_mentor(C, C, 1, 0, 0)]: [msg]")
@@ -59,16 +59,13 @@
to_chat(src, "Mentor PM to-[key_name_mentor(C, C, 1, 0, 0)]: [msg]")
else
- if(check_mentor()) //sender is an mentor but recipient is not.
+ if(is_mentor()) //sender is an mentor but recipient is not.
to_chat(C, "Mentor PM from-[key_name_mentor(src, C, 1, 0, 0)]: [msg]")
to_chat(src, "Mentor PM to-[key_name_mentor(C, C, 1, 0, show_char)]: [msg]")
//we don't use message_Mentors here because the sender/receiver might get it too
- var/show_char_sender = !check_mentor_other(src) && config.mentors_mobname_only
- var/show_char_recip = !check_mentor_other(C) && config.mentors_mobname_only
- for(var/client/X in GLOB.mentors)
+ var/show_char_sender = !is_mentor() && CONFIG_GET(flag/mentors_mobname_only)
+ var/show_char_recip = !C.is_mentor() && CONFIG_GET(flag/mentors_mobname_only)
+ for(var/client/X in GLOB.mentors | GLOB.admins)
if(X.key!=key && X.key!=C.key) //check client/X is an Mentor and isn't the sender or recipient
- to_chat(X, "Mentor PM: [key_name_mentor(src, X, 0, 0, show_char_sender)]->[key_name_mentor(C, X, 0, 0, show_char_recip)]: \blue [msg]") //inform X
- for(var/client/A in GLOB.admins)
- if(A.key!=key && A.key!=C.key) //check client/A is an Mentor and isn't the sender or recipient
- to_chat(A, "Mentor PM: [key_name_mentor(src, A, 0, 0, show_char_sender)]->[key_name_mentor(C, A, 0, 0, show_char_recip)]: \blue [msg]") //inform A
\ No newline at end of file
+ to_chat(X, "Mentor PM: [key_name_mentor(src, X, 0, 0, show_char_sender)]->[key_name_mentor(C, X, 0, 0, show_char_recip)]: [msg]") //inform X
\ No newline at end of file
diff --git a/code/modules/mentor/verbs/mentorsay.dm b/modular_citadel/code/modules/mentor/mentorsay.dm
similarity index 51%
rename from code/modules/mentor/verbs/mentorsay.dm
rename to modular_citadel/code/modules/mentor/mentorsay.dm
index 377761bb89..b921f8863a 100644
--- a/code/modules/mentor/verbs/mentorsay.dm
+++ b/modular_citadel/code/modules/mentor/mentorsay.dm
@@ -2,7 +2,8 @@
set category = "Mentor"
set name = "Msay" //Gave this shit a shorter name so you only have to time out "msay" rather than "mentor say" to use it --NeoFite
set hidden = 1
- if(!check_mentor()) return
+ if(!is_mentor())
+ return
msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
if(!msg) return
@@ -10,13 +11,8 @@
msg = emoji_parse(msg)
log_mentor("MSAY: [key_name(src)] : [msg]")
-
- if(check_rights(R_ADMIN,0))
- msg = "MENTOR: [key_name(src, 0, 0)]: [msg]"
- to_chat(GLOB.mentors, msg)
- to_chat(GLOB.admins, msg)
-
+ if(check_rights_for(src, R_ADMIN,0))
+ msg = "MENTOR: [key_name(src, 0, 0)]: [msg]"
else
- msg = "MENTOR: [key_name(src, 0, 0)]: [msg]"
- to_chat(GLOB.mentors, msg)
- to_chat(GLOB.admins, msg)
+ msg = "MENTOR: [key_name(src, 0, 0)]: [msg]"
+ to_chat(GLOB.admins | GLOB.mentors, msg)
diff --git a/tgstation.dme b/tgstation.dme
index be4a0fb9eb..826b39d6af 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1344,7 +1344,6 @@
#include "code\modules\client\verbs\ooc.dm"
#include "code\modules\client\verbs\ping.dm"
#include "code\modules\client\verbs\suicide.dm"
-#include "code\modules\client\verbs\who.dm"
#include "code\modules\clothing\chameleon.dm"
#include "code\modules\clothing\clothing.dm"
#include "code\modules\clothing\ears\_ears.dm"
@@ -2505,6 +2504,8 @@
#include "modular_citadel\code\init.dm"
#include "modular_citadel\code\__HELPERS\lists.dm"
#include "modular_citadel\code\__HELPERS\mobs.dm"
+#include "modular_citadel\code\_globalvars\lists\mobs.dm"
+#include "modular_citadel\code\controllers\configuration\entries\general.dm"
#include "modular_citadel\code\controllers\subsystem\cit_nightshift.dm"
#include "modular_citadel\code\controllers\subsystem\job.dm"
#include "modular_citadel\code\controllers\subsystem\shuttle.dm"
@@ -2520,9 +2521,14 @@
#include "modular_citadel\code\game\objects\items\devices\PDA\PDA.dm"
#include "modular_citadel\code\game\objects\items\devices\radio\shockcollar.dm"
#include "modular_citadel\code\game\objects\items\melee\eutactic_blades.dm"
+#include "modular_citadel\code\modules\admin\admin.dm"
+#include "modular_citadel\code\modules\admin\holder2.dm"
+#include "modular_citadel\code\modules\admin\secrets.dm"
+#include "modular_citadel\code\modules\admin\topic.dm"
#include "modular_citadel\code\game\objects\structures\beds_chairs\sofa.dm"
#include "modular_citadel\code\modules\cargo\console.dm"
#include "modular_citadel\code\modules\cargo\packs.dm"
+#include "modular_citadel\code\modules\client\client_procs.dm"
#include "modular_citadel\code\modules\client\preferences.dm"
#include "modular_citadel\code\modules\client\preferences_savefile.dm"
#include "modular_citadel\code\modules\client\loadout\_donator.dm"
@@ -2537,8 +2543,16 @@
#include "modular_citadel\code\modules\client\loadout\shoes.dm"
#include "modular_citadel\code\modules\client\loadout\suit.dm"
#include "modular_citadel\code\modules\client\loadout\uniform.dm"
+#include "modular_citadel\code\modules\client\verbs\who.dm"
#include "modular_citadel\code\modules\clothing\under.dm"
#include "modular_citadel\code\modules\crafting\recipes.dm"
+#include "modular_citadel\code\modules\mentor\follow.dm"
+#include "modular_citadel\code\modules\mentor\mentor.dm"
+#include "modular_citadel\code\modules\mentor\mentor_memo.dm"
+#include "modular_citadel\code\modules\mentor\mentor_verbs.dm"
+#include "modular_citadel\code\modules\mentor\mentorhelp.dm"
+#include "modular_citadel\code\modules\mentor\mentorpm.dm"
+#include "modular_citadel\code\modules\mentor\mentorsay.dm"
#include "modular_citadel\code\modules\mining\mine_items.dm"
#include "modular_citadel\code\modules\mob\living\banana_spider.dm"
#include "modular_citadel\code\modules\mob\living\carbon\human\human_defense.dm"