diff --git a/code/__DEFINES/voreconstants.dm b/code/__DEFINES/voreconstants.dm index a89f81f757a..43f71a88590 100644 --- a/code/__DEFINES/voreconstants.dm +++ b/code/__DEFINES/voreconstants.dm @@ -305,3 +305,5 @@ GLOBAL_LIST_INIT(prey_release_sounds, list( #define RADIOPREF_HEAR_RADIO_BLURBLES "hear_staticky_chittering" #define RADIOPREF_HEAR_RADIO_STATIC "hear_staticky_clicks" + +#define ADMIN_CHAT_FILTER_DMS "ADMIN_CHAT_FILTER_DMS" diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index f60fe43311e..7798b00b22a 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1199,7 +1199,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) /mob/dview/Destroy(force = FALSE) if(!ready_to_die) - stack_trace("ALRIGHT WHICH FUCKER TRIED TO DELETE *MY* DVIEW?") + stack_trace("ALRIGHT WHICH frickER TRIED TO DELETE *MY* DVIEW?") if (!force) return QDEL_HINT_LETMELIVE @@ -1707,6 +1707,31 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) if(clint) return clint +/// Takes in a client, mob, ckey, quid, or even prefs, and returns a mob +/proc/extract_mob(something) + if(isclient(something)) + var/client/clint = something + return clint.mob + if(ismob(something)) + return something + if(istext(something)) + var/client/C = LAZYACCESS(GLOB.directory, something) + if(C) + return C.mob + var/mob/critter = SSeconomy.quid2mob(something) + if(critter) + return critter + if(istype(something, /datum/preferences)) + var/datum/preferences/P = something + return P.parent.mob + +/// takes in something that may have preferences, and returns their quid, wot wot +/proc/extract_quid(something) + var/datum/preferences/P = extract_prefs(something) + if(!P) + return + return P.quester_uid + /// Takes in a client, mob, or ckey, and returns the ckey /proc/get_ckey(clientthing) var/client/clint @@ -1799,7 +1824,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) var/index = GaussianReacharound(mean, stddev, min, max) return index -/// takes in fuckin anything and outputs if its a player +/// takes in frickin anything and outputs if its a player /proc/isplayer(imput) if(istext(imput)) return !!LAZYACCESS(GLOB.directory, imput) diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index 56878471ad2..79f700a5fb5 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -85,7 +85,7 @@ #define ui_acti "EAST-3:24,SOUTH:5" #define ui_zonesel "EAST-1:28,SOUTH:5" #define ui_acti_alt "EAST-1:28,SOUTH:5" //alternative intent switcher for when the interface is hidden (F12) -#define ui_crafting "EAST-1:27,SOUTH+3:5" +#define ui_crafting "EAST-4:24,SOUTH+1:6" #define ui_building "EAST-1:27,SOUTH+2:7" #define ui_language_menu "EAST-1:27,SOUTH+2:22" #define ui_wield "EAST-1:10,SOUTH+1:23" @@ -169,6 +169,7 @@ #define ui_ghost_teleport "SOUTH:6,CENTER-0.25:24" #define ui_ghost_spawners "SOUTH:6,CENTER+0.75:24" #define ui_ghost_second_wind "SOUTH:38,CENTER-1.25:24" +#define ui_ghost_char_dir "SOUTH:38,CENTER-2.25:24" #define ui_ghost_move_up "SOUTH:6,CENTER+1.75:24" #define ui_ghost_move_down "SOUTH:6,CENTER+1.75:24" @@ -181,6 +182,6 @@ #define ui_resistdelay "EAST-3:24,SOUTH+1:4" #define ui_combat_toggle "EAST-4:22,SOUTH:5" -#define ui_boxcraft "EAST-4:22,SOUTH+1:6" +#define ui_boxcraft "EAST-4:24,SOUTH+1:6" #define ui_boxarea "EAST-4:6,SOUTH+1:6" #define ui_boxlang "EAST-5:22,SOUTH+1:6" diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm index 190c43cfa59..f624a0e46ee 100644 --- a/code/_onclick/hud/ghost.dm +++ b/code/_onclick/hud/ghost.dm @@ -52,6 +52,16 @@ var/mob/dead/observer/G = usr SSsecondwind.show_menu_to(G) +/atom/movable/screen/ghost/character_directory + name = "Character Directory" + icon = 'icons/mob/screen_gen.dmi' + icon_state = "chardir" + +/atom/movable/screen/ghost/character_directory/Click() + var/mob/dead/observer/G = usr + var/client/C = G.client + C.show_character_directory() + /atom/movable/screen/ghost/move_ghost_up name = "Move up" icon_state = "move_ghost_up" @@ -102,6 +112,11 @@ using.hud = src static_inventory += using + using = new /atom/movable/screen/ghost/character_directory() + using.screen_loc = ui_ghost_char_dir // THIS IS A DEFINE!!! + using.hud = src + static_inventory += using + using = new /atom/movable/screen/language_menu using.icon = ui_style // THIS IS A DEFINE!!! using.hud = src diff --git a/code/controllers/subsystem/chat.dm b/code/controllers/subsystem/chat.dm index d482c6a253d..a2a909e4a89 100644 --- a/code/controllers/subsystem/chat.dm +++ b/code/controllers/subsystem/chat.dm @@ -23,6 +23,9 @@ SUBSYSTEM_DEF(chat) var/flirt_debug = TRUE var/debug_block_radio_blurbles = FALSE + /// Format: list("quid" = /datum/character_inspection) + var/list/inspectors = list() + /// list of flirt ckey things so that we can store their target or something /// format: list("flirterckey" = "targetckey") var/list/active_flirters = list() @@ -88,11 +91,15 @@ SUBSYSTEM_DEF(chat) /datum/controller/subsystem/chat/fire() for(var/key in payload_by_client) var/client/client = key - var/payload = payload_by_client[key] + var/list/payload = payload_by_client[key] payload_by_client -= key if(client) - if(payload["prefCheck"] && CHECK_PREFS(client, payload["prefCheck"])) - continue // we dont want to see it + // for(var/pl_badwater in 1 to LAZYLEN(payload)) + // // Check if we should block this message + // var/list/control_point = LAZYACCESS(payload, pl_badwater) + // if(control_point["prefCheck"] && !CHECK_PREFS(client, control_point["prefCheck"])) + // payload.Cut(pl_badwater, pl_badwater-1) // Failmate + // continue // we dont want to see it // Send to tgchat client.tgui_panel?.window.send_message("chat/message", payload) // Send to old chat @@ -106,10 +113,14 @@ SUBSYSTEM_DEF(chat) for(var/_target in target) var/client/client = CLIENT_FROM_VAR(_target) if(client) + if(message["prefCheck"] && !CHECK_PREFS(client, message["prefCheck"])) + continue LAZYADD(payload_by_client[client], list(message)) return var/client/client = CLIENT_FROM_VAR(target) if(client) + if(message["prefCheck"] && !CHECK_PREFS(client, message["prefCheck"])) + return LAZYADD(payload_by_client[client], list(message)) /datum/controller/subsystem/chat/proc/build_flirt_datums() @@ -270,6 +281,92 @@ SUBSYSTEM_DEF(chat) /datum/controller/subsystem/chat/ui_state(mob/user) return GLOB.always_state +/datum/controller/subsystem/chat/proc/start_page(mob/sender, mob/reciever) + if(!sender || !reciever) + return + sender = extract_mob(sender) + if(!sender || !sender.client) + return + reciever = extract_mob(reciever) + if(!reciever || !reciever.client) + to_chat(sender, span_alert("Unable to contact user, please try again later!")) + return + if(is_blocked(sender, reciever)) + to_chat(sender, span_warning("Module failed to load.")) + return + var/theirname = name_or_shark(reciever) || "some jerk" // stop. naming. your. ckeys. after. your characcteres!!!!!!!!!!!!!!!!!! + var/mesage = input( + sender, + "Enter your message to [theirname]. This will send a direct message to them, which they can reply to! Be sure to respect their OOC preferences, don't be a creep (unless they like it), and have fun!", + "Direct OOC Message", + "" + ) as message|null + if(!mesage) + return + var/myname = name_or_shark(sender) || "some jerk" + var/payload2them = {"From [myname]: [mesage]
"} + payload2them = span_private(payload2them) + to_chat(reciever, span_private("
You have a new message from [name_or_shark(sender) || "Some jerk"]!")) + to_chat(reciever, payload2them) + var/payload2me = {"To [theirname]: [mesage]
"} + payload2me = span_private(payload2me) + to_chat(sender, span_private("
Your message to [theirname] has been sent!")) + to_chat(sender, payload2me) + sender.playsound_local(sender, 'sound/effects/direct_message_setn.ogg', 75, FALSE) + reciever.playsound_local(reciever, 'sound/effects/direct_message_recieved.ogg', 75, FALSE) + log_ooc("[sender.real_name] ([sender.ckey]) -> [reciever.real_name] ([reciever.ckey]): [mesage]") + message_admins("[ADMIN_TPMONTY(sender)] -DM-> [ADMIN_TPMONTY(reciever)]: [mesage]", ADMIN_CHAT_FILTER_DMS) + +/datum/controller/subsystem/chat/Topic(href, list/href_list) + . = ..() + if(href_list["DM"]) + start_page(href_list["sender_quid"], href_list["reciever_quid"]) + +/datum/controller/subsystem/chat/proc/is_blocked(mob/sender, mob/reciever) + return FALSE // todo: this + +/datum/controller/subsystem/chat/proc/name_or_shark(mob/they) + if(!istype(they)) + return "Nobody" + if(check_rights(R_ADMIN, FALSE)) + return they.real_name // we're an admin, we can see their name + if(isnewplayer(they)) + return they.client.prefs.my_shark + if(ckey(they.real_name) == ckey(they.ckey) || ckey(they.name) == ckey(they.ckey)) + if(strings("data/super_special_ultra_instinct.json", "[ckey(they.name)]", TRUE, TRUE)) + return they.name + if(strings("data/super_special_ultra_instinct.json", "[ckey(they.real_name)]", TRUE, TRUE)) + return they.real_name + if(they.client) + return they.client.prefs.my_shark + else + return "Some jerk" + return they.name + +/datum/controller/subsystem/chat/proc/inspect_character(mob/viewer, list/payload) + if(!viewer) + return + viewer = extract_mob(viewer) + if(!viewer || !viewer.client) + return + var/datum/character_inspection/chai = LAZYACCESS(inspectors, viewer.client.prefs.quester_uid) + if(!chai) + chai = new() + inspectors[viewer.client.prefs.quester_uid] = chai + chai.update(viewer, payload) + chai.show_to(viewer) + return TRUE + /datum/controller/subsystem/chat/proc/flirt_debug_toggle() TOGGLE_VAR(flirt_debug) build_flirt_datums() @@ -569,4 +666,113 @@ SUBSYSTEM_DEF(chat) message = replacetext(message, "THEIR", emoter.p_their()) return message +////////////// so those datums were awful, maybe this one will be better +/datum/character_inspection // DROP YOUR PANTS, ITS CHARACTER INSPECTION DAY + var/gender + var/species + var/vorepref + var/erppref + var/kisspref + var/flink + var/ad + var/notes + var/flavor + var/their_quid + var/looking_for_friends + var/dms_r_open + var/name + var/profile_pic + + /// update the character inspection with new data +/datum/character_inspection/proc/update(mob/viewer, list/payload) + if(!payload) + return + gender = payload["gender"] + species = payload["species"] + vorepref = payload["tag"] + erppref = payload["erptag"] + kisspref = payload["whokisser"] + flink = payload["flist"] + ad = payload["character_ad"] + notes = payload["ooc_notes"] + flavor = payload["flavor_text"] + their_quid = payload["quid"] + looking_for_friends = payload["looking_for_friends"] + dms_r_open = payload["dms_r_open"] + name = payload["name"] + profile_pic = payload["profile_pic"] + if(viewer && viewer.client) + show_to(viewer) + + /// show the character inspection to the viewer +/datum/character_inspection/proc/show_to(mob/viewer) + ui_interact(viewer) + +/datum/character_inspection/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "CharacterInspection") + ui.open() + ui.set_autoupdate(FALSE) + +/datum/character_inspection/ui_static_data(mob/user) + var/list/static_data = list() + static_data["gender"] = gender + static_data["species"] = species + static_data["vorepref"] = vorepref + static_data["erppref"] = erppref + static_data["kisspref"] = kisspref + static_data["flink"] = flink + static_data["ad"] = html_decode(ad) + static_data["notes"] = html_decode(notes) + static_data["flavor"] = html_decode(flavor) + static_data["their_quid"] = their_quid + static_data["name"] = name + static_data["looking_for_friends"] = looking_for_friends + static_data["dms_r_open"] = dms_r_open + static_data["profile_pic"] = profile_pic + if(user && user.client) // dont know why they wouldnt, but whatever + static_data["viewer_quid"] = user.client.prefs.quester_uid + return static_data + +/datum/character_inspection/ui_act(action, list/params) + . = ..() + if(!params["viewer_quid"]) + return + var/mob/viower = extract_mob(params["viewer_quid"]) + if(!viower) // warning: sum of dis chapta is extremely scray + return // viower excretion advisd + var/mob/viowed = extract_mob(params["their_quid"]) + if(!viowed) + return + if(action == "pager") + SSchat.start_page(viower, viowed) + return TRUE + if(action == "show_pic") + var/dat = {""} + var/datum/browser/popup = new(viower, "enlargeImage", "Full Sized Picture!",1024,768) + popup.set_content(dat) + popup.open() + return TRUE + if(action == "view_flist") + if(viowed) + to_chat(viower, span_notice("Opening F-list...")) + SEND_SIGNAL(viowed, COMSIG_FLIST, viower) + return TRUE + else + to_chat(viower, span_alert("Couldn't find that character's F-list!")) + return TRUE + return TRUE + +/datum/character_inspection/ui_state(mob/user) + return GLOB.always_state + +/mob/verb/direct_message(mob/A as mob in view(10, src)) + set name = "Direct Message" + set category = "OOC" + set desc = "Send a direct message to this character." + set popup_menu = TRUE + + SSchat.start_page(src, A) + diff --git a/code/controllers/subsystem/prefbreak.dm b/code/controllers/subsystem/prefbreak.dm index 1f785a2bbe0..b56392bda43 100644 --- a/code/controllers/subsystem/prefbreak.dm +++ b/code/controllers/subsystem/prefbreak.dm @@ -244,6 +244,14 @@ SUBSYSTEM_DEF(prefbreak) // ALL ABOARD THE S.S. PREFBREAK OFF TO **** YOUR ***** PREFBROKEN return CHECK_BITFIELD(consumer.chat_toggles, CHAT_HEAR_RADIOSTATIC) // kinda vital here +/// im an admin and i dont want to hear about how you want to destroy someone's bussy +/datum/prefcheck/admin_wire_tap + index = ADMIN_CHAT_FILTER_DMS + +/datum/prefcheck/admin_wire_tap/allowed(datum/preferences/consumer) + PREFBROKEN + return consumer.admin_wire_tap // kinda vital here + diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index a32785d1c79..3cf8d81d82c 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -66,6 +66,7 @@ var/list/ui_item_blocks var/current_maxscreensize + var/max_depth = STORAGE_VIEW_DEPTH var/allow_big_nesting = FALSE //allow storage objects of the same or greater size. @@ -336,7 +337,7 @@ /datum/component/storage/proc/check_views() for(var/mob/M in can_see_contents()) - if(!isobserver(M) && !M.can_reach(parent, STORAGE_VIEW_DEPTH)) + if(!isobserver(M) && !M.can_reach(parent, max_depth)) close(M) /datum/component/storage/proc/emp_act(datum/source, severity) diff --git a/code/datums/elements/flavor_text.dm b/code/datums/elements/flavor_text.dm index f1fe16d77a6..1a2f964b429 100644 --- a/code/datums/elements/flavor_text.dm +++ b/code/datums/elements/flavor_text.dm @@ -14,6 +14,7 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code var/save_key /// Do not attempt to render a preview on examine. If this is on, it will display as \[flavor_name\] var/examine_no_preview = FALSE + var/why_does_it_do_this = 0 /datum/element/flavor_text/Attach(datum/target, text = "", _name = "Flavor Text", _addendum, _max_len = MAX_FLAVOR_LEN, _always_show = FALSE, _edit = TRUE, _save_key, _examine_no_preview = FALSE, _attach_internet_link = FALSE) . = ..() @@ -110,11 +111,26 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code return TRUE /datum/element/flavor_text/proc/actually_show_flist(mob/living/carbon/human/H, mob/reader) - if(alert(reader, "This will open the following link '[H.dna.features["flist"]]' in your browser. Are you sure?","Open external link","Yes","No") =="Yes") - reader << link(H.dna.features["flist"]) - return TRUE - else + if(!H.dna.features["flist"]) + to_chat(reader, span_alert("They don't have an F-List link!")) return + to_chat(reader, span_green("The fancy F-List dialog box is broken :( so just imagine there's a cool window here with a button!")) + to_chat(reader, span_green("Click here for F-List: [H.dna.features["flist"]]")) + + // var/show_it = alert( + // reader, + // "This will open the following link '[H.dna.features["flist"]]' in your browser. Are you sure?", + // "Open external link", + // "Yes", + // "No" + // ) + // if(show_it == "Yes") + // if(prob(5)) + // to_chat(reader, span_alert("So be it.")) + // reader << link(H.dna.features["flist"]) + // return TRUE + // else + // return /mob/proc/manage_flavor_tests() set name = "Manage Flavor Texts" diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 67f64754799..a26a6de02ba 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -6,13 +6,13 @@ message_admins(finalMessage) log_world(finalMessage) -/proc/message_admins(msg) +/proc/message_admins(msg, pref) msg = "ADMIN LOG: [msg]" - to_chat(GLOB.admins, msg, confidential = TRUE) + to_chat(GLOB.admins, msg, confidential = TRUE, pref_check = pref) -/proc/relay_msg_admins(msg) +/proc/relay_msg_admins(msg, pref) msg = "RELAY: [msg]" - to_chat(GLOB.admins, msg, confidential = TRUE) + to_chat(GLOB.admins, msg, confidential = TRUE, pref_check = pref) ///////////////////////////////////////////////////////////////////////////////////////////////Panels diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index aaac22837c0..1bfebaf586d 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -14,6 +14,7 @@ GLOBAL_PROTECT(admin_verbs_default) /client/proc/toggleadminhelpsound, /client/proc/debugstatpanel, /client/proc/ignore_as_a_ghost, + /client/proc/toggle_admin_wire_tap, /client/proc/toggle_seeing_ghosts, /* Toggles whether or not the player can see ghosts */ /client/proc/RemoteLOOC, /*Fuck you I'm a PascaleCase enjoyer when it comes to functions. Fuck you nerds for using your shitty ass underscores like you know what the fuck you're reading why add an extra character and waste a couple milimeters of eye movement for me to read your entire proc name like jesus fucking christ bro. Just literally use PascalCase it looks so much neater, it's modern, industry professionals are taught to use it, C# coding standards state this, C++ coding standards, Unreal Engine developers do this, and so do Unity professionals. Like bruh please. Join me in the revolution to do PascalCase. */ // Welcome to byond~ src.grab_antlers_and_grind(deer_boi) ) @@ -688,6 +689,16 @@ GLOBAL_PROTECT(admin_verbs_hideable) P.save_preferences() to_chat(usr, "Preferences saved.") +/client/proc/toggle_admin_wire_tap() + set category = "OOC" + set name = "Ignore Others' DMs" + set desc = "Blocks seeing DMs from players to players who arent you." + + TOGGLE_VAR(prefs.admin_wire_tap) + prefs.save_preferences() + to_chat(src, span_abductor("You will [prefs.admin_wire_tap ? "now" : "no longer"] eavesdrop on other players' DMs.")) + to_chat(src, "Preferences saved.") + /client/proc/give_spell(mob/T in GLOB.mob_list) set category = "Admin.Fun" set name = "Give Spell" diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 95a80b91c5b..f09407cc7f9 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -83,6 +83,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/pda_color = "#808000" var/pda_skin = PDA_SKIN_CLASSIC + var/my_shark = "Bingus Whale" + var/genital_whitelist = "" var/whoflags = DEFAULT_WHO_FLAGS var/lockouts = NONE @@ -146,6 +148,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/kisser = KISS_DEFAULT // Kiss this ( Y ) /// which quester UID we're using var/quester_uid + var/dm_open = TRUE + var/needs_a_friend = FALSE // for the quest + var/list/blocked_from_dms = list() // list of quids /// rough approximations of the character's finished quests var/list/saved_finished_quests = list() /// tight list of the character's active quests @@ -154,6 +159,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/datum/species/pref_species = new /datum/species/mammal() //Mutant race /// If our species supports it, this will override our appearance. See species.dm. "Default" will just use the base icon var/alt_appearance = "Default" + var/admin_wire_tap = TRUE var/list/features = list( "mcolor" = "FFFFFF", "mcolor2" = "FFFFFF", @@ -397,6 +403,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) /datum/preferences/New(client/C) parent = C + if(LAZYLEN(GLOB.cow_names)) + my_shark = safepick(GLOB.cow_names + GLOB.carp_names + GLOB.megacarp_last_names) spawn(0) if(C) chatbgcolor = winget(C, "statbrowser", "background-color") diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 099d3129981..8a923e96524 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -319,6 +319,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["genital_whitelist"] >> genital_whitelist S["lockouts"] >> lockouts // my bans! + S["admin_wire_tap"] >> admin_wire_tap // my bans! chat_toggles |= CHAT_LOOC // the LOOC doesn't stop @@ -377,6 +378,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car key_bindings = sanitize_islist(key_bindings, list()) modless_key_bindings = sanitize_islist(modless_key_bindings, list()) aghost_squelches = sanitize_islist(aghost_squelches, list()) + admin_wire_tap = sanitize_integer(admin_wire_tap, TRUE) verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped @@ -490,10 +492,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["lockouts"], lockouts) WRITE_FILE(S["aghost_squelches"], aghost_squelches) WRITE_FILE(S["genital_whitelist"], genital_whitelist) - - //permanent tattoos - WRITE_FILE(S["permanent_tattoos"], permanent_tattoos) - return 1 + WRITE_FILE(S["admin_wire_tap"], admin_wire_tap) /datum/preferences/proc/load_character(slot) if(!path) @@ -940,9 +939,12 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //Permanent Tattoos S["permanent_tattoos"] >> permanent_tattoos + S["dm_open"] >> dm_open + S["needs_a_friend"] >> needs_a_friend //Permanent Tattoos faved_interactions = safe_json_decode(S["faved_interactions"]) + blocked_from_dms = safe_json_decode(S["blocked_from_dms"]) /// Test if they have a saved quid, if not, generate one. var/saved_quid @@ -970,6 +972,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car faved_interactions = sanitize_islist(faved_interactions, list()) saved_finished_quests = sanitize_islist(saved_finished_quests, list()) saved_active_quests = sanitize_islist(saved_active_quests, list()) + dm_open = sanitize_integer(dm_open, TRUE) + needs_a_friend = sanitize_integer(needs_a_friend, TRUE) //Sanitize @@ -1410,6 +1414,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["feature_flist"], features["flist"]) WRITE_FILE(S["feature_taste"], features["taste"]) + WRITE_FILE(S["dm_open"], dm_open) + WRITE_FILE(S["needs_a_friend"], needs_a_friend) //special WRITE_FILE(S["special_s"] ,special_s) @@ -1558,6 +1564,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //permanent tattoos WRITE_FILE(S["permanent_tattoos"], permanent_tattoos) + WRITE_FILE(S["blocked_from_dms"], safe_json_encode(blocked_from_dms)) //permanent tattoos WRITE_FILE(S["faved_interactions"], safe_json_encode(faved_interactions)) if(LAZYLEN(saved_finished_quests)) diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi index d042eb10b46..6d137f76e0e 100644 Binary files a/icons/mob/screen_gen.dmi and b/icons/mob/screen_gen.dmi differ diff --git a/modular_sand/code/controllers/subsystem/interactions.dm b/modular_sand/code/controllers/subsystem/interactions.dm index 26245a1b918..bdc2ff3049b 100644 --- a/modular_sand/code/controllers/subsystem/interactions.dm +++ b/modular_sand/code/controllers/subsystem/interactions.dm @@ -155,6 +155,7 @@ SUBSYSTEM_DEF(interactions) to_chat(target, span_greentext("You have given [requesting] consent to do lewd things with you!")) if(requesting) to_chat(requesting, span_greentext("[target] has given you consent to do lewd things with them!")) + message_admins("[ADMIN_TPMONTY(requesting)] requested consent from [ADMIN_TPMONTY(target)]. [target] said yes!") /// consenting! target declined consent /datum/controller/subsystem/interactions/proc/decline_consent(mob/decliner, mob/denied, ahelp) @@ -165,6 +166,7 @@ SUBSYSTEM_DEF(interactions) to_chat(decliner, span_userdanger("You have declined [denied]'s request to do lewd things with you!")) log_ooc("[key_name_admin(decliner)] has declined [key_name_admin(denied)]'s request to do lewd things with them!") if(!ahelp) + message_admins("[ADMIN_TPMONTY(decliner)] declined consent from [ADMIN_TPMONTY(denied)].") return log_ooc("[key_name_admin(decliner)] has also requested an admin regarding [key_name_admin(denied)]'s request to do lewd things with them!") to_chat(decliner, span_userdanger("An admin will be with you shortly!!!")) @@ -219,6 +221,7 @@ SUBSYSTEM_DEF(interactions) consents -= keyname to_chat(revoked, span_userdanger("[revoker] has revoked consent for you to do lewd things with them!")) to_chat(revoker, span_userdanger("You have revoked consent from [revoked] to do lewd things with you!")) + message_admins("[ADMIN_TPMONTY(revoker)] has revoked [ADMIN_TPMONTY(revoked)]'s consent to do lewd things with them. (Original approver: [original_approver])") log_ooc("[key_name_admin(revoker)] has revoked [key_name_admin(revoked)]'s consent to do lewd things with them! (Original approver: [key_name_admin(original_approver)])") if(ahelp) log_ooc("[key_name_admin(revoker)] has also requested an admin regarding [key_name_admin(revoked)]'s consent to do lewd things with them!") diff --git a/modular_splurt/code/datums/modules/client/verbs/character_directory.dm b/modular_splurt/code/datums/modules/client/verbs/character_directory.dm index 675c923a6f6..8b8da0f9002 100644 --- a/modular_splurt/code/datums/modules/client/verbs/character_directory.dm +++ b/modular_splurt/code/datums/modules/client/verbs/character_directory.dm @@ -35,38 +35,40 @@ GLOBAL_LIST_INIT(char_directory_erptags, list("Top", "Bottom", "Switch", "No ERP /datum/character_directory/ui_data(mob/user) . = ..() - var/list/data = . + var/list/data = list() + data["personalName"] = user.real_name 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" var/adtext = user.client.prefs.directory_ad - if(LAZYLEN(adtext) > 85) - adtext = copytext(adtext, 1, 128) + "..." + if(LAZYLEN(adtext) > 256) + adtext = copytext(adtext, 1, 256) + "..." else if(!adtext) adtext = "Unset" data["personalAdvert"] = adtext - var/fucktext = user.client.prefs.features["flist"] - if(!fucktext) - fucktext = "Unset" - data["personalFlist"] = fucktext || "Unset" + var/fricktext = user.client.prefs.features["flist"] + if(!fricktext) + fricktext = "Unset" + data["personalFlist"] = fricktext || "Unset" data["prefsOnly"] = TRUE - + data["personalDMs"] = user.client.prefs.dm_open + data["personalQuid"] = user.client.prefs.quester_uid + data["personalLookingForFriends"] = user.client.prefs.needs_a_friend data["canOrbit"] = isobserver(user) - return data +// return data -/datum/character_directory/ui_static_data(mob/user) - . = ..() - var/list/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.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/ref = REF(C?.mob) @@ -82,7 +84,7 @@ GLOBAL_LIST_INIT(char_directory_erptags, list("Top", "Bottom", "Switch", "No ERP var/tag = "Unset" var/erptag = "Unset" var/character_ad = "Unset" - var/fucklist = "Unset" + var/fricklist = "Unset" tag = C.prefs.directory_tag || "Unset" erptag = C.prefs.directory_erptag || "Unset" character_ad = C.prefs.directory_ad @@ -98,7 +100,7 @@ GLOBAL_LIST_INIT(char_directory_erptags, list("Top", "Bottom", "Switch", "No ERP whokisser = "Not Interested" if((isdead(M) && (lowertext(M.real_name) == M.ckey || lowertext(M.name) == M.ckey))) - name = pick(GLOB.cow_names + GLOB.carp_names + GLOB.megacarp_last_names) + name = C.prefs.my_shark // 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) @@ -117,7 +119,7 @@ GLOBAL_LIST_INIT(char_directory_erptags, list("Top", "Bottom", "Switch", "No ERP ooc_notes = C.prefs.features["ooc_notes"] flavor_text = C.prefs.features["flavor_text"] - fucklist = C.prefs.features["flist"] || FALSE + fricklist = C.prefs.features["flist"] || FALSE directory_mobs.Add(list(list( "name" = name, @@ -130,7 +132,11 @@ GLOBAL_LIST_INIT(char_directory_erptags, list("Top", "Bottom", "Switch", "No ERP "ref" = ref, "gender" = thegender, "whokisser" = whokisser, - "flist" = fucklist, + "flist" = fricklist, + "quid" = C.prefs.quester_uid, // love is a quest, and I'm on a quest for love + "dms_r_open" = C.prefs.dm_open, + "looking_for_friends" = C.prefs.needs_a_friend, + "profile_pic" = PfpHostLink(C.prefs.profilePicture, C.prefs.pfphost) ))) data["directory"] = directory_mobs @@ -166,13 +172,41 @@ GLOBAL_LIST_INIT(char_directory_erptags, list("Top", "Bottom", "Switch", "No ERP ghost.reset_perspective(null) return TRUE if("view_flist") - var/ref = params["ref"] - var/atom/movable/poi = (locate(ref) in GLOB.mob_list) || (locate(ref) in GLOB.poi_list) - if (poi == null) + var/mob/them = extract_mob(params["quid"]) + if(them) + to_chat(user, span_notice("Opening F-list...")) + SEND_SIGNAL(them, COMSIG_FLIST, user) + return TRUE + else + to_chat(user, span_alert("Couldn't find that character's F-list!")) return TRUE - return SEND_SIGNAL(poi, COMSIG_FLIST, user) + if("inspect") + var/list/payload = list() + payload["quid"] = params["quid"] + payload["my_quid"] = params["my_quid"] + payload["name"] = params["name"] + payload["species"] = params["species"] + payload["ooc_notes"] = params["ooc_notes"] + payload["tag"] = params["tag"] + payload["erptag"] = params["erptag"] + payload["character_ad"] = params["character_ad"] + payload["flavor_text"] = params["flavor_text"] + payload["ref"] = params["ref"] + payload["gender"] = params["gender"] + payload["whokisser"] = params["whokisser"] + payload["flist"] = params["flist"] + payload["quid"] = params["quid"] + payload["dms_r_open"] = params["dms_r_open"] + payload["looking_for_friends"] = params["looking_for_friends"] + payload["profile_pic"] = params["profile_pic"] + SSchat.inspect_character(user, payload) + if("pager") + SSchat.start_page(user, params["quid"]) + if("setLookingForFriends") + TOGGLE_VAR(user.client.prefs.needs_a_friend) else return check_for_mind_or_prefs(user, action, params["overwrite_prefs"]) + return TRUE /datum/character_directory/proc/check_for_mind_or_prefs(mob/user, action, overwrite_prefs) if (!user.client) @@ -198,22 +232,35 @@ GLOBAL_LIST_INIT(char_directory_erptags, list("Top", "Bottom", "Switch", "No ERP var/visible = user.client.prefs.show_in_directory to_chat(user, "You are now [!visible ? "shown" : "not shown"] in the directory.") return set_for_mind_or_prefs(user, action, !visible) + if ("setDMs") + var/doom2 = user.client.prefs.dm_open + to_chat(user, "You are [!doom2 ? "now open for" : "no longer open for"] direct OOC messaging.") + return set_for_mind_or_prefs(user, action, !doom2) if ("editAd") var/current_ad = user.client.prefs.directory_ad - var/new_ad = stripped_multiline_input_or_reflect(user, "Change your character ad", "Character Ad", current_ad, MAX_FLAVOR_LEN) + var/new_ad = stripped_multiline_input_or_reflect(user, "Change your character ad. Most HTML is supported! =3", "Character Ad", current_ad, MAX_FLAVOR_LEN) if(isnull(new_ad)) to_chat(user, span_notice("Okay! Your ad has not been changed!")) return return set_for_mind_or_prefs(user, action, new_ad) if ("editFlist") var/current_flist = user.client.prefs.features["flist"] - var/new_flist = stripped_input(user, "Change your character flist", "Character Flist", current_flist, 256) // flist links are less than 256 characters, right? - if(isnull(new_flist)) + var/link = stripped_input( + user, + "Set always-visible F-list. Just copy and paste the link you want to use from the browser. Leave it blank to remove the previous link.", + "F-list", + current_flist, + 256 + ) + if(!length(link)) + set_for_mind_or_prefs(user, action, link) + to_chat(usr, span_alert("Removed the previous F-list link.")) + else if(findtext(link, "https://www.f-list.net")) //we want to avoid malicious links, so let's check if it's actually a valid link first + set_for_mind_or_prefs(user, action, link) + to_chat(usr, span_green("F-list link added!")) + if(isnull(link)) to_chat(user, span_notice("Okay! Your flist has not been changed!")) return - return set_for_mind_or_prefs(user, action, new_flist) - else - to_chat(user, 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) if(!user || !user.client) @@ -224,6 +271,8 @@ GLOBAL_LIST_INIT(char_directory_erptags, list("Top", "Bottom", "Switch", "No ERP switch(action) if ("setTag") P.directory_tag = new_value + if ("setDMs") + P.dm_open = new_value if ("setErpTag") P.directory_erptag = new_value if ("setVisible") diff --git a/sound/effects/direct_message_recieved.ogg b/sound/effects/direct_message_recieved.ogg new file mode 100644 index 00000000000..0c2dc83bc20 Binary files /dev/null and b/sound/effects/direct_message_recieved.ogg differ diff --git a/sound/effects/direct_message_setn.ogg b/sound/effects/direct_message_setn.ogg new file mode 100644 index 00000000000..2c150e2939b Binary files /dev/null and b/sound/effects/direct_message_setn.ogg differ diff --git a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss index dd2cb393b75..8d34515f619 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss @@ -1021,7 +1021,7 @@ em { .private { color: #00BB80; - font-weight: bold; + // font-weight: bold; animation: private 3000ms; animation-direction: linear; } diff --git a/tgui/packages/tgui-panel/styles/goon/chat-light.scss b/tgui/packages/tgui-panel/styles/goon/chat-light.scss index ebae4d0f2d4..549e7172068 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-light.scss @@ -1104,7 +1104,7 @@ h1.alert, h2.alert { .private { color: #00BB80; - font-weight: bold; + // font-weight: bold; animation: private 3000ms; animation-direction: linear; } diff --git a/tgui/packages/tgui/components/Section.tsx b/tgui/packages/tgui/components/Section.tsx index dc226fad611..7580ee15adb 100644 --- a/tgui/packages/tgui/components/Section.tsx +++ b/tgui/packages/tgui/components/Section.tsx @@ -20,6 +20,7 @@ interface SectionProps extends BoxProps { level?: boolean; /** @deprecated Please use `scrollable` property */ overflowY?: any; + smallTitle?: boolean; } export class Section extends Component { @@ -52,6 +53,7 @@ export class Section extends Component { fill, fitted, scrollable, + smallTitle, children, ...rest } = this.props; @@ -70,9 +72,15 @@ export class Section extends Component { {...computeBoxProps(rest)}> {hasTitle && (
- - {title} - + {smallTitle && ( + + {title} + + ) || ( + + {title} + + )}
{buttons}
diff --git a/tgui/packages/tgui/interfaces/CharacterDirectory.js b/tgui/packages/tgui/interfaces/CharacterDirectory.js index e378a6809cf..f85da538b98 100644 --- a/tgui/packages/tgui/interfaces/CharacterDirectory.js +++ b/tgui/packages/tgui/interfaces/CharacterDirectory.js @@ -1,6 +1,16 @@ +/* eslint-disable */ import { Fragment } from 'inferno'; import { useBackend, useLocalState } from '../backend'; -import { Box, Button, Icon, LabeledList, Section, Table, Stack } from '../components'; +import { + Box, + Button, + Icon, + LabeledList, + Section, + Table, + Flex, + Tabs, + Stack } from '../components'; import { Window } from '../layouts'; const erpTagColor = { @@ -15,146 +25,257 @@ export const CharacterDirectory = (props, context) => { const { act, data } = useBackend(context); const { + personalName, personalVisibility, personalTag, personalErpTag, prefsOnly, personalAdvert, personalFlist, + personalDMs, } = data; - const [overlay, setOverlay] = useLocalState(context, 'overlay', null); - const [overwritePrefs, setOverwritePrefs] = useLocalState(context, 'overwritePrefs', prefsOnly); + const [ + SelectedTab, + setSelectedTab, + ] = useLocalState(context, 'SelectedTab', 1); return ( - - - {(overlay && ) || ( - + + + +
- - Save to current preferences slot:  - - + ); +} + +// / The main window! either your characters or the available characters +const MainWindow = (props, context) => { // main screen turn on + const { act, data } = useBackend(context); + + const [ + SelectedTab, + setSelectedTab, + ] = useLocalState(context, 'SelectedTab', 1); + + + return ( + <> + {SelectedTab === 1 && ( + + )} + {SelectedTab === 2 && ( + + )} + {SelectedTab === 3 && ( + + )} + + ); +}; + +const SettingsControl = (props, context) => { + const { act, data } = useBackend(context); + const { + personalName, + personalVisibility, + personalTag, + personalErpTag, + prefsOnly, + personalAdvert, + personalFlist, + personalDMs, + } = data; + const [overwritePrefs, setOverwritePrefs] = useLocalState(context, 'overwritePrefs', prefsOnly); return (
setOverlay(null)} />}> -
- {overlay.gender} -
-
- {overlay.species} -
-
- {overlay.tag} -
-
- - {overlay.erptag} - -
-
- {overlay.whokisser} -
-
- {overlay.flist_link} -
-
- - {overlay.character_ad || 'Unset.'} - -
-
- - {overlay.ooc_notes || 'Unset.'} - -
-
- - {overlay.flavor_text || 'Unset.'} - -
+ title="Controls" + buttons={ + + {/* + Save to current preferences slot:  + +
+ ); +}; + +const ReadMe = (props, context) => { + const { act, data } = useBackend(context); + const { ReadmeText } = data; + + return ( +
+
); }; +const BottomToolbar = (props, context) => { + const { act, data } = useBackend(context); + const { personalLookingForFriends } = data; + + return ( + + + + + + +