From f74b876b5e04fcffe4805ffe867eb4112a12c11a Mon Sep 17 00:00:00 2001
From: BongaTheProto <93835010+BongaTheProto@users.noreply.github.com>
Date: Sat, 20 May 2023 15:38:43 -0500
Subject: [PATCH] we've got a new menu boys
those crewmembers are looking quite exquisite today
also felinids are half-price
---
code/modules/client/preferences_savefile.dm | 4 +
.../_globalvars/lists/character_directory.dm | 2 +
modular_splurt/code/datums/mind.dm | 20 ++
.../code/modules/client/preferences.dm | 4 +
.../modules/client/preferences_savefile.dm | 20 ++
.../client/verbs/character_directory.dm | 212 +++++++++++++++++
tgstation.dme | 2 +
.../tgui/interfaces/CharacterDirectory.js | 217 ++++++++++++++++++
8 files changed, 481 insertions(+)
create mode 100644 modular_splurt/code/_globalvars/lists/character_directory.dm
create mode 100644 modular_splurt/code/modules/client/verbs/character_directory.dm
create mode 100644 tgui/packages/tgui/interfaces/CharacterDirectory.js
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index aad17eb424..134e91db52 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -1300,6 +1300,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
cit_character_pref_load(S)
+ splurt_character_pref_load(S)
+
return 1
/datum/preferences/proc/save_character(bypass_cooldown = FALSE)
@@ -1545,6 +1547,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
cit_character_pref_save(S)
+ splurt_character_pref_save(S)
+
return 1
diff --git a/modular_splurt/code/_globalvars/lists/character_directory.dm b/modular_splurt/code/_globalvars/lists/character_directory.dm
new file mode 100644
index 0000000000..a308e81e94
--- /dev/null
+++ b/modular_splurt/code/_globalvars/lists/character_directory.dm
@@ -0,0 +1,2 @@
+GLOBAL_LIST_INIT(char_directory_tags, list("Pred", "Pred-Pref", "Prey", "Prey-Pref", "Switch", "Non-Vore", "Unset"))
+GLOBAL_LIST_INIT(char_directory_erptags, list("Top", "Bottom", "Switch", "No ERP", "Unset"))
diff --git a/modular_splurt/code/datums/mind.dm b/modular_splurt/code/datums/mind.dm
index 78a06ad7cb..e1eca4be65 100644
--- a/modular_splurt/code/datums/mind.dm
+++ b/modular_splurt/code/datums/mind.dm
@@ -1,3 +1,23 @@
+/datum/mind
+ var/show_in_directory
+ var/directory_tag
+ var/directory_erptag
+ var/directory_ad
+ var/ooc_notes
+ var/flavor_text
+ var/silicon_flavor_text
+
+/mob/living/mind_initialize()
+ . = ..()
+ if(client?.prefs)
+ mind.show_in_directory = client?.prefs.show_in_directory
+ mind.directory_tag = client?.prefs.directory_tag
+ mind.directory_erptag = client?.prefs.directory_erptag
+ mind.directory_ad = client?.prefs.directory_ad
+ mind.ooc_notes = client?.prefs.features["ooc_notes"]
+ mind.flavor_text = client?.prefs.features["flavor_text"]
+ mind.silicon_flavor_text = client?.prefs.features["silicon_flavor_text"]
+
/datum/mind/proc/remove_slaver()
var/datum/antagonist/slaver/slaver = has_antag_datum(/datum/antagonist/slaver,TRUE)
if(slaver)
diff --git a/modular_splurt/code/modules/client/preferences.dm b/modular_splurt/code/modules/client/preferences.dm
index 3ceec318df..444380e2fe 100644
--- a/modular_splurt/code/modules/client/preferences.dm
+++ b/modular_splurt/code/modules/client/preferences.dm
@@ -8,6 +8,10 @@
var/unholypref = "No" //Goin 2 hell fo dis one
var/list/gfluid_blacklist = list() //Stuff you don't want people to cum into you
var/new_character_creator = TRUE // old/new character creator
+ var/show_in_directory = 1 //Show in Character Directory
+ var/directory_tag = "Unset" //Sorting tag to use in character directory
+ var/directory_erptag = "Unset" //ditto, but for non-vore scenes
+ var/directory_ad = "" //Advertisement stuff to show in character directory.
/datum/preferences/New(client/C)
// Check if readable fluids list exists
diff --git a/modular_splurt/code/modules/client/preferences_savefile.dm b/modular_splurt/code/modules/client/preferences_savefile.dm
index 5471d37fd4..deda14d0e1 100644
--- a/modular_splurt/code/modules/client/preferences_savefile.dm
+++ b/modular_splurt/code/modules/client/preferences_savefile.dm
@@ -1,3 +1,23 @@
+/datum/preferences/proc/splurt_character_pref_load(savefile/S) //TODO: modularize our other savefile edits... maybe?
+ //Character directory
+ S["show_in_directory"] >> show_in_directory
+ S["directory_tag"] >> directory_tag
+ S["directory_erptag"] >> directory_erptag
+ S["directory_ad"] >> directory_ad
+
+ //sanitize data
+ show_in_directory = sanitize_integer(show_in_directory, 0, 1, initial(show_in_directory))
+ directory_tag = sanitize_inlist(directory_tag, GLOB.char_directory_tags, initial(directory_tag))
+ directory_erptag = sanitize_inlist(directory_erptag, GLOB.char_directory_erptags, initial(directory_erptag))
+ directory_ad = strip_html_simple(directory_ad, MAX_FLAVOR_LEN)
+
+/datum/preferences/proc/splurt_character_pref_save(savefile/S) //TODO: modularize our other savefile edits... maybe?
+ //Character directory
+ WRITE_FILE(S["show_in_directory"], show_in_directory)
+ WRITE_FILE(S["directory_tag"], directory_tag)
+ WRITE_FILE(S["directory_erptag"], directory_erptag)
+ WRITE_FILE(S["directory_ad"], directory_ad)
+
/datum/preferences/update_preferences(current_version, savefile/S)
. = ..()
if(current_version < 57.01) //a
diff --git a/modular_splurt/code/modules/client/verbs/character_directory.dm b/modular_splurt/code/modules/client/verbs/character_directory.dm
new file mode 100644
index 0000000000..2fa14e9223
--- /dev/null
+++ b/modular_splurt/code/modules/client/verbs/character_directory.dm
@@ -0,0 +1,212 @@
+GLOBAL_DATUM(character_directory, /datum/character_directory)
+
+/client
+ COOLDOWN_DECLARE(char_directory_cooldown)
+
+/client/verb/show_character_directory()
+ set name = "Character Directory"
+ set category = "OOC"
+ set desc = "Shows a listing of all active characters, along with their associated OOC notes, flavor text, and more."
+
+ // This is primarily to stop malicious users from trying to lag the server by spamming this verb
+ if(!COOLDOWN_FINISHED(src, char_directory_cooldown))
+ to_chat(usr, "Don't spam character directory refresh.")
+ return
+ COOLDOWN_START(src, char_directory_cooldown, 10)
+
+ if(!GLOB.character_directory)
+ GLOB.character_directory = new
+ GLOB.character_directory.ui_interact(mob)
+
+
+// This is a global singleton. Keep in mind that all operations should occur on usr, not src.
+/datum/character_directory
+
+/datum/character_directory/ui_state(mob/user)
+ return GLOB.always_state
+
+/datum/character_directory/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "CharacterDirectory", "Character Directory")
+ ui.open()
+
+/datum/character_directory/ui_data(mob/user)
+ . = ..()
+ var/list/data = .
+
+ if (user?.mind && !isdead(user))
+ data["personalVisibility"] = user.mind.show_in_directory
+ data["personalTag"] = user.mind.directory_tag || "Unset"
+ data["personalErpTag"] = user.mind.directory_erptag || "Unset"
+ data["prefsOnly"] = FALSE
+ else if (user?.client?.prefs)
+ data["personalVisibility"] = user.client.prefs.show_in_directory
+ data["personalTag"] = user.client.prefs.directory_tag || "Unset"
+ data["personalErpTag"] = user.client.prefs.directory_erptag || "Unset"
+ data["prefsOnly"] = TRUE
+
+ return data
+
+/datum/character_directory/ui_static_data(mob/user)
+ . = ..()
+ var/list/data = .
+
+ var/list/directory_mobs = list()
+ for(var/client/C in GLOB.clients)
+ // Allow opt-out and filter players not in the game
+ if(C?.mob?.mind ? !C.mob.mind.show_in_directory : !C?.prefs?.show_in_directory)
+ continue
+
+ // These are the three vars we're trying to find
+ // The approach differs based on the mob the client is controlling
+ var/name = null
+ var/species = null
+ var/ooc_notes = null
+ var/flavor_text = null
+ var/tag
+ var/erptag
+ var/character_ad
+ if (C.mob?.mind) //could use ternary for all three but this is more efficient
+ tag = C.mob.mind.directory_tag || "Unset"
+ erptag = C.mob.mind.directory_erptag || "Unset"
+ character_ad = C.mob.mind.directory_ad
+ else
+ tag = C.prefs.directory_tag || "Unset"
+ erptag = C.prefs.directory_erptag || "Unset"
+ character_ad = C.prefs.directory_ad
+
+ if(ishuman(C.mob))
+ var/mob/living/carbon/human/H = C.mob
+ if(GLOB.data_core && GLOB.data_core.general)
+ if(!find_record("name", H.real_name, GLOB.data_core.general))
+ continue
+ name = H.real_name
+ species = "[H.custom_species ? H.custom_species : H.dna.species]"
+ ooc_notes = H.mind.ooc_notes
+ flavor_text = H.mind.flavor_text
+
+ if(isAI(C.mob))
+ var/mob/living/silicon/ai/A = C.mob
+ name = A.name
+ species = "Artificial Intelligence"
+ ooc_notes = A.mind.ooc_notes
+ flavor_text = null // No flavor text for AIs :c
+
+ if(iscyborg(C.mob))
+ var/mob/living/silicon/robot/R = C.mob
+ if(R.scrambledcodes)
+ continue
+ name = R.name
+ species = "Cyborg"
+ ooc_notes = R.mind.ooc_notes
+ flavor_text = R.mind.silicon_flavor_text
+
+ // It's okay if we fail to find OOC notes and flavor text
+ // But if we can't find the name, they must be using a non-compatible mob type currently.
+ if(!name)
+ continue
+
+ directory_mobs.Add(list(list(
+ "name" = name,
+ "species" = species,
+ "ooc_notes" = ooc_notes,
+ "tag" = tag,
+ "erptag" = erptag,
+ "character_ad" = character_ad,
+ "flavor_text" = flavor_text,
+ )))
+
+ data["directory"] = directory_mobs
+
+ return data
+
+/datum/character_directory/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+
+ if(.)
+ return
+
+ if(action == "refresh")
+ // This is primarily to stop malicious users from trying to lag the server by spamming this verb
+ if(!COOLDOWN_FINISHED(usr.client, char_directory_cooldown))
+ to_chat(usr, "Don't spam character directory refresh.")
+ return
+ COOLDOWN_START(usr.client, char_directory_cooldown, 10)
+ update_static_data(usr, ui)
+ return TRUE
+ else
+ return check_for_mind_or_prefs(usr, action, params["overwrite_prefs"])
+
+/datum/character_directory/proc/check_for_mind_or_prefs(mob/user, action, overwrite_prefs)
+ if (!user.client)
+ return
+ var/can_set_prefs = overwrite_prefs && !!user.client.prefs
+ var/can_set_mind = !!user.mind && !isdead(user)
+ if (!can_set_prefs && !can_set_mind)
+ if (!overwrite_prefs && !!user.client.prefs)
+ to_chat(user, "You cannot change these settings if you don't have a mind to save them to. Enable overwriting prefs and switch to a slot you're fine with overwriting.")
+ return
+ switch(action)
+ if ("setTag")
+ var/list/new_tag = tgui_input_list(usr, "Pick a new Vore tag for the character directory", "Character Tag", GLOB.char_directory_tags)
+ if(!new_tag)
+ return
+ return set_for_mind_or_prefs(user, action, new_tag, can_set_prefs, can_set_mind)
+ if ("setErpTag")
+ var/list/new_erptag = tgui_input_list(usr, "Pick a new ERP tag for the character directory", "Character ERP Tag", GLOB.char_directory_erptags)
+ if(!new_erptag)
+ return
+ return set_for_mind_or_prefs(user, action, new_erptag, can_set_prefs, can_set_mind)
+ if ("setVisible")
+ var/visible = TRUE
+ if (can_set_mind)
+ visible = user.mind.show_in_directory
+ else if (can_set_prefs)
+ visible = user.client.prefs.show_in_directory
+ to_chat(usr, "You are now [!visible ? "shown" : "not shown"] in the directory.")
+ return set_for_mind_or_prefs(user, action, !visible, can_set_prefs, can_set_mind)
+ if ("editAd")
+ var/current_ad = (can_set_mind ? usr.mind.directory_ad : null) || (can_set_prefs ? usr.client.prefs.directory_ad : null)
+ var/new_ad = strip_html_simple(tgui_input_text(usr, "Change your character ad", "Character Ad", current_ad, MAX_FLAVOR_LEN, multiline = TRUE, prevent_enter = TRUE), MAX_FLAVOR_LEN)
+ if(isnull(new_ad))
+ return
+ return set_for_mind_or_prefs(user, action, new_ad, can_set_prefs, can_set_mind)
+ else
+ to_chat(usr, span_warning("You can only make temporary changes while in game"))
+
+/datum/character_directory/proc/set_for_mind_or_prefs(mob/user, action, new_value, can_set_prefs, can_set_mind)
+ can_set_prefs &&= !!user.client.prefs
+ can_set_mind &&= !!user.mind
+ if (!can_set_prefs && !can_set_mind)
+ to_chat(user, "You seem to have lost either your mind, or your current preferences, while changing the values.[action == "editAd" ? " Here is your ad that you wrote. [new_value]" : null]")
+ return
+ switch(action)
+ if ("setTag")
+ if (can_set_prefs)
+ user.client.prefs.directory_tag = new_value
+ user.client.prefs.save_character()
+ if (can_set_mind)
+ user.mind.directory_tag = new_value
+ return TRUE
+ if ("setErpTag")
+ if (can_set_prefs)
+ user.client.prefs.directory_erptag = new_value
+ user.client.prefs.save_character()
+ if (can_set_mind)
+ user.mind.directory_erptag = new_value
+ return TRUE
+ if ("setVisible")
+ if (can_set_prefs)
+ user.client.prefs.show_in_directory = new_value
+ user.client.prefs.save_character()
+ if (can_set_mind)
+ user.mind.show_in_directory = new_value
+ return TRUE
+ if ("editAd")
+ if (can_set_prefs)
+ user.client.prefs.directory_ad = new_value
+ user.client.prefs.save_character()
+ if (can_set_mind)
+ user.mind.directory_ad = new_value
+ return TRUE
diff --git a/tgstation.dme b/tgstation.dme
index 0165558c72..d1142d8fa7 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -4323,6 +4323,7 @@
#include "modular_splurt\code\__HELPERS\text.dm"
#include "modular_splurt\code\__HELPERS\unsorted.dm"
#include "modular_splurt\code\_globalvars\tgui.dm"
+#include "modular_splurt\code\_globalvars\lists\character_directory.dm"
#include "modular_splurt\code\_globalvars\lists\global_lewd.dm"
#include "modular_splurt\code\_globalvars\lists\mapping.dm"
#include "modular_splurt\code\_globalvars\lists\mobs.dm"
@@ -4614,6 +4615,7 @@
#include "modular_splurt\code\modules\client\loadout\donator\first_tier.dm"
#include "modular_splurt\code\modules\client\loadout\donator\second_tier.dm"
#include "modular_splurt\code\modules\client\loadout\donator\third_tier.dm"
+#include "modular_splurt\code\modules\client\verbs\character_directory.dm"
#include "modular_splurt\code\modules\client\verbs\looc.dm"
#include "modular_splurt\code\modules\client\verbs\ooc.dm"
#include "modular_splurt\code\modules\clothing\back.dm"
diff --git a/tgui/packages/tgui/interfaces/CharacterDirectory.js b/tgui/packages/tgui/interfaces/CharacterDirectory.js
new file mode 100644
index 0000000000..00c6c4b94b
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/CharacterDirectory.js
@@ -0,0 +1,217 @@
+import { Fragment } from 'inferno';
+import { useBackend, useLocalState } from '../backend';
+import { Box, Button, Icon, LabeledList, Section, Table } from '../components';
+import { Window } from '../layouts';
+
+/* //General erp preferences are probably a better indicator for this station
+ const getErpTagColor = (tag) => {
+ switch (tag) {
+ case 'Unset':
+ return 'label';
+ case 'Pred':
+ return 'red';
+ case 'Pred-Pref':
+ return 'orange';
+ case 'Prey':
+ return 'blue';
+ case 'Prey-Pref':
+ return 'green';
+ case 'Switch':
+ return 'yellow';
+ case 'Non-Vore':
+ return 'black';
+ }
+};*/
+
+const getErpTagColor = (tag) => {
+ switch (tag) {
+ case 'Unset':
+ return 'label';
+ case 'Top':
+ return 'red';
+ case 'Bottom':
+ return 'blue';
+ case 'Switch':
+ return 'yellow';
+ case 'No ERP':
+ return 'black';
+ }
+};
+
+export const CharacterDirectory = (props, context) => {
+ const { act, data } = useBackend(context);
+
+ const { personalVisibility, personalTag, personalErpTag, prefsOnly } = data;
+
+ const [overlay, setOverlay] = useLocalState(context, 'overlay', null);
+
+ const [overwritePrefs, setOverwritePrefs] = useLocalState(context, 'overwritePrefs', prefsOnly);
+
+ return (
+
+
+