From 475fe94750732c8b4e4ad218b2b55c996e90bffa Mon Sep 17 00:00:00 2001 From: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Date: Sun, 26 Apr 2026 00:20:58 -0400 Subject: [PATCH] Say verb & skin shenanigans (Pray is a hotkey, Whisper is in commandbar) (#95477) ## About The Pull Request Removes Say/Me/OOC/Pray/Whisper as stat panel verbs 1. Adds a hotkey for Pray, P by default, and also adds it to the list of say modes (so tabbing on tgui-say will show it) 2. Makes Whisper a button on the commandbar, which is literally just ``say "#``, letting players know it exists in a more direct manner. 3. You now need 2 characters to be considered "typing", so `#` for whisper won't cause you to start to think anymore. Also messes around with the skin a bit, moving the commandbar to be separate from the chat window, therefore not resizing if the chat window/stat panel splitter changes, since I was already messing with the command bar entirely I might as well look into getting this fixed. This will go even better with https://github.com/tgstation/tgstation/pull/95383 as it wont stretch the command bar when the stat panel is closed. https://github.com/user-attachments/assets/26cd9df0-7582-445e-9f67-c03d2c9cf46d Also adds a new Adminhelp submenu for the Pray button for additional visibility https://github.com/user-attachments/assets/64f31f86-92a2-4f04-b248-6bbe301919fe My current goal is the deletion of the IC tab so I've been trying to inch towards that. ## Why It's Good For The Game Moves Praying & Whispering into something that's more easily seen by newer players, and helps cut some of the more useless verbs out of the stat panel. This is also part of my project you can see more of here - https://hackmd.io/443_dE5lRWeEAp9bjGcKYw?view ## Changelog :cl: qol: Pray verb is now a hotkey, Whisper is now a command bar button, and all say verbs have been removed from the stat panel. qol: Admin button on the escape menu is now its own section for praying, as well as seeing your latest ticket & admin notes. fix: Resizing the stat panel will no longer change the size of the command bar. /:cl: --- code/__DEFINES/keybinding.dm | 1 + code/__DEFINES/say.dm | 8 ++ code/__DEFINES/speech_channels.dm | 1 + code/datums/keybinding/communication.dm | 30 +++++ code/modules/admin/verbs/pray.dm | 39 +++--- code/modules/client/verbs/ooc.dm | 3 +- code/modules/client/verbs/typing.dm | 2 +- code/modules/escape_menu/admin_page.dm | 83 ++++++++++++ code/modules/escape_menu/escape_menu.dm | 10 ++ code/modules/escape_menu/home_page.dm | 4 +- .../escape_menu/screen_objects/admin_text.dm | 93 +++++-------- .../escape_menu/screen_objects/text.dm | 2 +- code/modules/mob/mob_say.dm | 12 +- code/modules/tgui_input/say_modal/modal.dm | 2 +- code/modules/tgui_input/say_modal/speech.dm | 7 +- interface/skin.dmf | 126 +++++++++++------- tgstation.dme | 1 + tgui/packages/tgui-panel/settings/scaling.ts | 5 +- tgui/packages/tgui-panel/settings/themes.ts | 2 + .../packages/tgui-say/ChannelIterator.test.ts | 1 + tgui/packages/tgui-say/ChannelIterator.ts | 6 +- tgui/packages/tgui-say/styles/colors.scss | 1 + 22 files changed, 293 insertions(+), 146 deletions(-) create mode 100644 code/modules/escape_menu/admin_page.dm diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm index 1e88e16d5d7..73da7d1924c 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -39,6 +39,7 @@ #define COMSIG_KB_CLIENT_RADIO_DOWN "keybinding_client_radio_down" #define COMSIG_KB_CLIENT_ME_DOWN "keybinding_client_me_down" #define COMSIG_KB_CLIENT_OOC_DOWN "keybinding_client_ooc_down" +#define COMSIG_KB_CLIENT_PRAY_DOWN "keybinding_client_pray_down" //Human #define COMSIG_KB_HUMAN_QUICKEQUIP_DOWN "keybinding_human_quickequip_down" diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index 9b8496f22fd..cf31b1e69f9 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -146,3 +146,11 @@ ///Defines for priorities for the bubble_icon_override comp #define BUBBLE_ICON_PRIORITY_ACCESSORY 2 #define BUBBLE_ICON_PRIORITY_ORGAN 1 + +//These are the names of the commands, what you'd need to type to do the command (also used in winset) +#define VERB_SAY "Say" +#define VERB_WHISPER "Whisper" +#define VERB_ME "Me" +//Gave this shit a shorter name so you only have to time out "ooc" rather than "ooc message" to use it --NeoFite +#define VERB_OOC "OOC" +#define VERB_PRAY "Pray" diff --git a/code/__DEFINES/speech_channels.dm b/code/__DEFINES/speech_channels.dm index 9f1526ebd56..3cd5b40374e 100644 --- a/code/__DEFINES/speech_channels.dm +++ b/code/__DEFINES/speech_channels.dm @@ -4,3 +4,4 @@ #define ME_CHANNEL "Me" #define OOC_CHANNEL "OOC" #define ADMIN_CHANNEL "Admin" +#define PRAY_CHANNEL "Pray" diff --git a/code/datums/keybinding/communication.dm b/code/datums/keybinding/communication.dm index bc77eee0f93..a5aa6981243 100644 --- a/code/datums/keybinding/communication.dm +++ b/code/datums/keybinding/communication.dm @@ -11,6 +11,9 @@ . = ..() if(.) return + if(!user.prefs.read_preference(/datum/preference/toggle/tgui_input)) + winset(user, null, "command=[VERB_SAY]") + return TRUE winset(user, null, "command=[user.tgui_say_create_open_command(SAY_CHANNEL)];") winset(user, "tgui_say.browser", "focus=true") return TRUE @@ -25,6 +28,9 @@ . = ..() if(.) return + if(!user.prefs.read_preference(/datum/preference/toggle/tgui_input)) + winset(user, null, "command=[VERB_SAY]") + return TRUE winset(user, null, "command=[user.tgui_say_create_open_command(RADIO_CHANNEL)]") winset(user, "tgui_say.browser", "focus=true") return TRUE @@ -39,6 +45,9 @@ . = ..() if(.) return + if(!user.prefs.read_preference(/datum/preference/toggle/tgui_input)) + winset(user, null, "command=[VERB_OOC]") + return TRUE winset(user, null, "command=[user.tgui_say_create_open_command(OOC_CHANNEL)]") winset(user, "tgui_say.browser", "focus=true") return TRUE @@ -53,6 +62,27 @@ . = ..() if(.) return + if(!user.prefs.read_preference(/datum/preference/toggle/tgui_input)) + winset(user, null, "command=[VERB_ME]") + return TRUE winset(user, null, "command=[user.tgui_say_create_open_command(ME_CHANNEL)]") winset(user, "tgui_say.browser", "focus=true") return TRUE + +/datum/keybinding/client/communication/pray + hotkey_keys = list("P") + name = PRAY_CHANNEL + full_name = "Pray" + description = "Allows you to directly send a message to your deity (Admins) in an IC manner." + keybind_signal = COMSIG_KB_CLIENT_PRAY_DOWN + +/datum/keybinding/client/communication/pray/down(client/user, turf/target, mousepos_x, mousepos_y) + . = ..() + if(.) + return + if(!user.prefs.read_preference(/datum/preference/toggle/tgui_input)) + winset(user, null, "command=[VERB_PRAY]") + return TRUE + winset(user, null, "command=[user.tgui_say_create_open_command(PRAY_CHANNEL)];") + winset(user, "tgui_say.browser", "focus=true") + return TRUE diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index 4277cae7d81..aefd988aa74 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -1,51 +1,50 @@ -/mob/verb/pray(msg as text) - set category = "IC" - set name = "Pray" +/mob/verb/pray(message as text) + set name = VERB_PRAY if(GLOB.say_disabled) //This is here to try to identify lag problems - to_chat(usr, span_danger("Speech is currently admin-disabled."), confidential = TRUE) + to_chat(src, span_danger("Speech is currently admin-disabled."), confidential = TRUE) return - msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN) - if(!msg) + message = copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN) + if(!message) return - log_prayer("[src.key]/([src.name]): [msg]") - if(usr.client) - if(usr.client.prefs.muted & MUTE_PRAY) - to_chat(usr, span_danger("You cannot pray (muted)."), confidential = TRUE) + log_prayer("[src.key]/([src.name]): [message]") + if(src.client) + if(src.client.prefs.muted & MUTE_PRAY) + to_chat(src, span_danger("You cannot pray (muted)."), confidential = TRUE) return - if(src.client.handle_spam_prevention(msg,MUTE_PRAY)) + if(src.client.handle_spam_prevention(message, MUTE_PRAY)) return var/mutable_appearance/cross = mutable_appearance('icons/obj/storage/book.dmi', "bible") var/font_color = "purple" var/prayer_type = "PRAYER" var/deity - if(usr.job == JOB_CHAPLAIN) + if(src.job == JOB_CHAPLAIN) cross.icon_state = "kingyellow" font_color = "blue" prayer_type = "CHAPLAIN PRAYER" if(GLOB.deity) deity = GLOB.deity - else if(IS_CULTIST(usr)) + else if(IS_CULTIST(src)) cross.icon_state = "tome" font_color = "red" prayer_type = "CULTIST PRAYER" deity = "Nar'Sie" - else if(isliving(usr)) - var/mob/living/L = usr + else if(isliving(src)) + var/mob/living/L = src if(HAS_TRAIT(L, TRAIT_SPIRITUAL)) cross.icon_state = "holylight" font_color = "blue" prayer_type = "SPIRITUAL PRAYER" - var/msg_tmp = msg - GLOB.requests.pray(usr.client, msg, usr.job == JOB_CHAPLAIN) - msg = span_adminnotice("[icon2html(cross, GLOB.admins)][prayer_type][deity ? " (to [deity])" : ""]: [ADMIN_FULLMONTY(src)] [ADMIN_SC(src)]: [span_linkify(msg)]") + var/msg_tmp = message + GLOB.requests.pray(src.client, message, src.job == JOB_CHAPLAIN) + message = span_adminnotice("[icon2html(cross, GLOB.admins)][prayer_type][deity ? " (to [deity])" : ""]: [ADMIN_FULLMONTY(src)] [ADMIN_SC(src)]: [span_linkify(message)]") for(var/client/C in GLOB.admins) if(get_chat_toggles(C) & CHAT_PRAYER) - to_chat(C, msg, type = MESSAGE_TYPE_PRAYER, confidential = TRUE) - to_chat(usr, span_info("You pray to the gods: \"[msg_tmp]\""), confidential = TRUE) + to_chat(C, message, type = MESSAGE_TYPE_PRAYER, confidential = TRUE) + to_chat(src, span_info("You pray to the gods: \"[msg_tmp]\""), confidential = TRUE) BLACKBOX_LOG_ADMIN_VERB("Prayer") diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index b1a95e81c2b..a25299089e2 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -3,8 +3,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8") ///talking in OOC uses this /client/verb/ooc(msg as text) - set name = "OOC" //Gave this shit a shorter name so you only have to time out "ooc" rather than "ooc message" to use it --NeoFite - set category = "OOC" + set name = VERB_OOC if(GLOB.say_disabled) //This is here to try to identify lag problems to_chat(usr, span_danger("Speech is currently admin-disabled.")) diff --git a/code/modules/client/verbs/typing.dm b/code/modules/client/verbs/typing.dm index b7a73622614..bef6d85a048 100644 --- a/code/modules/client/verbs/typing.dm +++ b/code/modules/client/verbs/typing.dm @@ -9,7 +9,7 @@ /client/proc/handle_commandbar_typing(href_list) if (!typing_indicators) //check pref return - if (length(href_list["verb"]) < 1 || !(LOWER_TEXT(href_list["verb"]) in IC_VERBS) || text2num(href_list["argument_length"]) < 1) + if (length(href_list["verb"]) < 1 || !(LOWER_TEXT(href_list["verb"]) in IC_VERBS) || text2num(href_list["argument_length"]) < 2) if (commandbar_typing) commandbar_typing = FALSE stop_typing() diff --git a/code/modules/escape_menu/admin_page.dm b/code/modules/escape_menu/admin_page.dm new file mode 100644 index 00000000000..3eeacf70e93 --- /dev/null +++ b/code/modules/escape_menu/admin_page.dm @@ -0,0 +1,83 @@ +/datum/escape_menu/proc/show_admin_page() + page_holder.give_screen_object( + new /atom/movable/screen/escape_menu/lobby_button/small( + null, + /* hud_owner = */ null, + "Back", + /* tooltip_text = */ null, + /* button_screen_loc = */ "TOP:-30,LEFT:30", + CALLBACK(src, PROC_REF(open_home_page)), + /* button_overlay = */ "back", + ) + ) + + page_holder.give_screen_object( + new /atom/movable/screen/escape_menu/text/clickable/admin_help( + null, + /* hud_owner = */ null, + /* escape_menu = */ src, + /* button_text = */ "Create Admin Ticket", + /* offset = */ list(-136, 28), + /* font_size = */ 24, + /* on_click_callback = */ CALLBACK(src, PROC_REF(create_ticket)), + ) + ) + + page_holder.give_screen_object( + new /atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification( + null, + /* hud_owner = */ null, + /* escape_menu = */ src, + /* button_text = */ "View Latest Ticket", + /* offset = */ list(-171, 28), + /* font_size = */ 24, + /* on_click_callback = */ CALLBACK(src, PROC_REF(view_latest_ticket)), + ) + ) + page_holder.give_screen_object( + new /atom/movable/screen/escape_menu/text/clickable( + null, + /* hud_owner = */ null, + /* escape_menu = */ src, + /* button_text = */ "Pray", + /* offset = */ list(-206, 30), + /* font_size = */ 24, + /* on_click_callback = */ CALLBACK(src, PROC_REF(pray)), + ) + ) + + if(CONFIG_GET(flag/see_own_notes)) + page_holder.give_screen_object( + new /atom/movable/screen/escape_menu/text/clickable( + null, + /* hud_owner = */ null, + /* escape_menu = */ src, + /* button_text = */ "See Notes", + /* offset = */ list(-241, 30), + /* font_size = */ 24, + /* on_click_callback = */ CALLBACK(src, PROC_REF(see_notes)), + ) + ) + +/datum/escape_menu/proc/create_ticket() + if(!(/client/verb/adminhelp in client?.verbs)) + return + client?.adminhelp() + qdel(src) + +///Opens your latest admin ticket. +/datum/escape_menu/proc/view_latest_ticket() + client?.view_latest_ticket() + +///Manually calls the user's pray() hotkey (which is where prefs is taken into account). +/datum/escape_menu/proc/pray() + var/datum/keybinding/client/communication/pray/pray_verb = GLOB.keybindings_by_name[/datum/keybinding/client/communication/pray::name] + pray_verb.down(client) + qdel(src) + +/datum/escape_menu/proc/see_notes() + if(!CONFIG_GET(flag/see_own_notes)) + to_chat(client.mob, span_notice("Seeing notes has been disabled on this server.")) + return + browse_messages(null, client.ckey, null, TRUE) + qdel(src) diff --git a/code/modules/escape_menu/escape_menu.dm b/code/modules/escape_menu/escape_menu.dm index 53940e0ae07..8e86d78d647 100644 --- a/code/modules/escape_menu/escape_menu.dm +++ b/code/modules/escape_menu/escape_menu.dm @@ -16,6 +16,7 @@ GLOBAL_LIST_EMPTY(escape_menus) new /datum/escape_menu(src) #define PAGE_HOME "PAGE_HOME" +#define PAGE_ADMIN "ADMIN_PAGE" #define PAGE_LEAVE_BODY "PAGE_LEAVE_BODY" #define PAGE_QUIT_GAME "PAGE_QUIT_GAME" @@ -126,6 +127,8 @@ GLOBAL_LIST_EMPTY(escape_menus) switch (menu_page) if (PAGE_HOME) show_home_page() + if (PAGE_ADMIN) + show_admin_page() if (PAGE_LEAVE_BODY) show_leave_body_page() if(PAGE_QUIT_GAME) @@ -145,6 +148,12 @@ GLOBAL_LIST_EMPTY(escape_menus) menu_page = PAGE_HOME show_page() +/datum/escape_menu/proc/open_admin_page() + PRIVATE_PROC(TRUE) + + menu_page = PAGE_ADMIN + show_page() + /datum/escape_menu/proc/open_leave_body() PRIVATE_PROC(TRUE) @@ -162,5 +171,6 @@ GLOBAL_LIST_EMPTY(escape_menus) clear_with_screen = FALSE #undef PAGE_HOME +#undef PAGE_ADMIN #undef PAGE_LEAVE_BODY #undef PAGE_QUIT_GAME diff --git a/code/modules/escape_menu/home_page.dm b/code/modules/escape_menu/home_page.dm index 641be0d3a34..aead9cc8d51 100644 --- a/code/modules/escape_menu/home_page.dm +++ b/code/modules/escape_menu/home_page.dm @@ -37,12 +37,14 @@ ) page_holder.give_screen_object( - new /atom/movable/screen/escape_menu/text/clickable/admin_help( + new /atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification( null, /* hud_owner = */ null, /* escape_menu = */ src, /* button_text = */ "Admin Help", /* offset = */ list(-241, 30), + /* font_size = */ 24, + /* on_click_callback = */ CALLBACK(src, PROC_REF(open_admin_page)), ) ) diff --git a/code/modules/escape_menu/screen_objects/admin_text.dm b/code/modules/escape_menu/screen_objects/admin_text.dm index 2a7260785b3..abedf2cba3f 100644 --- a/code/modules/escape_menu/screen_objects/admin_text.dm +++ b/code/modules/escape_menu/screen_objects/admin_text.dm @@ -1,12 +1,12 @@ -/atom/movable/screen/escape_menu/text/clickable/admin_help +///Text that gets highlighted when you have an admin ticket notification. +/atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification VAR_PRIVATE current_blink = FALSE is_blinking = FALSE last_blink_time = 0 - blink_interval = 0.4 SECONDS -/atom/movable/screen/escape_menu/text/clickable/admin_help/Initialize( +/atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification/Initialize( mapload, datum/hud/hud_owner, datum/escape_menu/escape_menu, @@ -18,7 +18,6 @@ . = ..() RegisterSignal(escape_menu.client, COMSIG_ADMIN_HELP_RECEIVED, PROC_REF(on_admin_help_received)) - RegisterSignals(escape_menu.client, list(COMSIG_CLIENT_VERB_ADDED, COMSIG_CLIENT_VERB_REMOVED), PROC_REF(on_client_verb_changed)) var/datum/admin_help/current_ticket = escape_menu.client?.current_ticket if (!isnull(current_ticket)) @@ -26,48 +25,12 @@ if (!current_ticket?.player_replied) begin_processing() -/atom/movable/screen/escape_menu/text/clickable/admin_help/Click(location, control, params) - if (!enabled()) - return - - QDEL_IN(escape_menu, 0) - - var/client/client = escape_menu.client - - if (has_open_adminhelp()) - client?.view_latest_ticket() - else - client?.adminhelp() - -/atom/movable/screen/escape_menu/text/clickable/admin_help/proc/has_open_adminhelp() - var/client/client = escape_menu.client - - var/datum/admin_help/current_ticket = client?.current_ticket - - // This is null with a closed ticket. - // This is okay since the View Latest Ticket panel already tells you if your ticket is closed, intentionally. - if (isnull(current_ticket)) - return FALSE - - // If we sent a ticket, but nobody has responded, send another one instead. - // Not worth opening a menu when there's nothing to read, you're only going to want to send. - if (length(current_ticket.admins_involved - client?.ckey) == 0) - return FALSE - - return TRUE - -/atom/movable/screen/escape_menu/text/clickable/admin_help/proc/on_admin_help_received() +/atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification/proc/on_admin_help_received() SIGNAL_HANDLER begin_processing() -/atom/movable/screen/escape_menu/text/clickable/admin_help/proc/on_client_verb_changed(client/source, list/verbs_changed) - SIGNAL_HANDLER - - if (/client/verb/adminhelp in verbs_changed) - update_text() - -/atom/movable/screen/escape_menu/text/clickable/admin_help/proc/begin_processing() +/atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification/proc/begin_processing() if (is_blinking) return @@ -76,7 +39,7 @@ START_PROCESSING(SSescape_menu, src) update_text() -/atom/movable/screen/escape_menu/text/clickable/admin_help/proc/end_processing() +/atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification/proc/end_processing() if (!is_blinking) return @@ -85,26 +48,17 @@ STOP_PROCESSING(SSescape_menu, src) update_text() -/atom/movable/screen/escape_menu/text/clickable/admin_help/proc/connect_ticket(datum/admin_help/admin_help) +/atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification/proc/connect_ticket(datum/admin_help/admin_help) ASSERT(istype(admin_help)) RegisterSignal(admin_help, COMSIG_ADMIN_HELP_REPLIED, PROC_REF(on_admin_help_replied)) -/atom/movable/screen/escape_menu/text/clickable/admin_help/proc/on_admin_help_replied() +/atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification/proc/on_admin_help_replied() SIGNAL_HANDLER end_processing() -/atom/movable/screen/escape_menu/text/clickable/admin_help/enabled() - if (!..()) - return FALSE - - if (!has_open_adminhelp()) - return /client/verb/adminhelp in escape_menu.client?.verbs - - return TRUE - -/atom/movable/screen/escape_menu/text/clickable/admin_help/process(seconds_per_tick) +/atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification/process(seconds_per_tick) if (world.time - last_blink_time < blink_interval) return @@ -112,19 +66,42 @@ last_blink_time = world.time update_text() -/atom/movable/screen/escape_menu/text/clickable/admin_help/text_color() +/atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification/text_color() if (!enabled()) return ..() return current_blink ? "red" : ..() -/atom/movable/screen/escape_menu/text/clickable/admin_help/MouseEntered(location, control, params) +/atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification/MouseEntered(location, control, params) . = ..() if (is_blinking) openToolTip(usr, src, params, content = "An admin is trying to talk to you!") -/atom/movable/screen/escape_menu/text/clickable/admin_help/MouseExited(location, control, params) +/atom/movable/screen/escape_menu/text/clickable/admin_ticket_notification/MouseExited(location, control, params) . = ..() closeToolTip(usr) + +///The button used for adminhelping, this is used to grey it out when you're on cooldown. +/atom/movable/screen/escape_menu/text/clickable/admin_help/Initialize( + mapload, + datum/hud/hud_owner, + datum/escape_menu/escape_menu, + button_text, + list/offset, + font_size = 24, + on_click_callback, +) + . = ..() + + RegisterSignals(escape_menu.client, list(COMSIG_CLIENT_VERB_ADDED, COMSIG_CLIENT_VERB_REMOVED), PROC_REF(on_client_verb_changed)) + +/atom/movable/screen/escape_menu/text/clickable/admin_help/proc/on_client_verb_changed(client/source, list/verbs_changed) + SIGNAL_HANDLER + + if (/client/verb/adminhelp in verbs_changed) + update_text() + +/atom/movable/screen/escape_menu/text/clickable/admin_help/enabled() + return (/client/verb/adminhelp in escape_menu.client?.verbs) diff --git a/code/modules/escape_menu/screen_objects/text.dm b/code/modules/escape_menu/screen_objects/text.dm index fe08bd021dc..529bd034c86 100644 --- a/code/modules/escape_menu/screen_objects/text.dm +++ b/code/modules/escape_menu/screen_objects/text.dm @@ -23,7 +23,7 @@ //this decides how far out you can 'click' on this, so it's important to keep it short. //yes even here, maptext can still embed links without using clickable subtype. - src.maptext_width = round((max(length(button_text), 20) * (font_size / 2.25)), 1) + src.maptext_width = max(round(length(button_text) * font_size * 0.75), font_size * 4) src.maptext_height = (maptext_height * (font_size / 5)) src.maptext_height *= length(splittext(button_text, "\n")) diff --git a/code/modules/mob/mob_say.dm b/code/modules/mob/mob_say.dm index 568df514fdf..920439d1091 100644 --- a/code/modules/mob/mob_say.dm +++ b/code/modules/mob/mob_say.dm @@ -2,9 +2,7 @@ ///what clients use to speak. when you type a message into the chat bar in say mode, this is the first thing that goes off serverside. /mob/verb/say_verb(message as text) - set name = "Say" - set category = "IC" - set instant = TRUE + set name = VERB_SAY if(GLOB.say_disabled) //This is here to try to identify lag problems to_chat(usr, span_danger("Speech is currently admin-disabled.")) @@ -17,9 +15,7 @@ ///Whisper verb /mob/verb/whisper_verb(message as text) - set name = "Whisper" - set category = "IC" - set instant = TRUE + set name = VERB_WHISPER if(GLOB.say_disabled) //This is here to try to identify lag problems to_chat(usr, span_danger("Speech is currently admin-disabled.")) @@ -40,9 +36,7 @@ ///The me emote verb /mob/verb/me_verb(message as text) - set name = "Me" - set category = "IC" - set desc = "Perform a custom emote. Leave blank to pick between an audible or a visible emote (Defaults to visible)." + set name = VERB_ME if(GLOB.say_disabled) //This is here to try to identify lag problems to_chat(usr, span_danger("Speech is currently admin-disabled.")) diff --git a/code/modules/tgui_input/say_modal/modal.dm b/code/modules/tgui_input/say_modal/modal.dm index 054c656d2e9..5dc6d7d9a97 100644 --- a/code/modules/tgui_input/say_modal/modal.dm +++ b/code/modules/tgui_input/say_modal/modal.dm @@ -92,7 +92,7 @@ if(!payload?["channel"]) CRASH("No channel provided to an open TGUI-Say") window_open = TRUE - if(payload["channel"] != OOC_CHANNEL && payload["channel"] != ADMIN_CHANNEL) + if(payload["channel"] != OOC_CHANNEL && payload["channel"] != ADMIN_CHANNEL && payload["channel"] != PRAY_CHANNEL) start_thinking() if(!client.typing_indicators) log_speech_indicators("[key_name(client)] started typing at [loc_name(client.mob)], indicators DISABLED.") diff --git a/code/modules/tgui_input/say_modal/speech.dm b/code/modules/tgui_input/say_modal/speech.dm index d27e7cfc0fd..79f604af6d5 100644 --- a/code/modules/tgui_input/say_modal/speech.dm +++ b/code/modules/tgui_input/say_modal/speech.dm @@ -12,7 +12,7 @@ var/list/phrases = alter_phrases || hurt_phrases /// No OOC leaks - if(!entry || payload["channel"] == OOC_CHANNEL || payload["channel"] == ME_CHANNEL) + if(!entry || payload["channel"] == OOC_CHANNEL || payload["channel"] == ME_CHANNEL || payload["channel"] == PRAY_CHANNEL) return pick(phrases) /// Random trimming for larger sentences if(length(entry) > 50) @@ -50,6 +50,9 @@ if(ADMIN_CHANNEL) INVOKE_ASYNC(SSadmin_verbs, TYPE_PROC_REF(/datum/controller/subsystem/admin_verbs, dynamic_invoke_verb), client, /datum/admin_verb/cmd_admin_say, entry) return TRUE + if(PRAY_CHANNEL) + client.mob.pray(entry) + return TRUE return FALSE /** @@ -129,7 +132,7 @@ return TRUE if(type == "force") var/target_channel = payload["channel"] - if(target_channel == ME_CHANNEL || target_channel == OOC_CHANNEL) + if(target_channel == ME_CHANNEL || target_channel == OOC_CHANNEL || target_channel == PRAY_CHANNEL) target_channel = SAY_CHANNEL // No ooc leaks delegate_speech(alter_entry(payload), target_channel) return TRUE diff --git a/interface/skin.dmf b/interface/skin.dmf index 366919f4b1c..2b9460cd8ca 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -138,7 +138,6 @@ window "info_and_buttons" size = 640x477 anchor1 = 0,0 anchor2 = 100,100 - background-color = #ffc41f saved-params = "splitter" left = "infobuttons" right = "infowindow" @@ -149,23 +148,71 @@ window "info_and_buttons" window "infowindow" elem "infowindow" type = MAIN - pos = 281,0 + pos = 281,5 size = 640x475 anchor1 = -1,-1 anchor2 = -1,-1 saved-params = "pos;size;is-minimized;is-maximized" is-pane = true - elem "info" + elem "info_split" type = CHILD pos = 0,5 + anchor1 = 0,0 + anchor2 = 100,100 + size = 640x475 + is-vert = false + splitter = 97.5 + background-color = #ffc41f + show-splitter = false + saved-params = "splitter" + left = "info" + right = "input_buttons" + +window "info" + elem "info_main" + type = MAIN + pos = 0,0 + size = 640x475 + anchor1 = 0,0 + anchor2 = 100,100 + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true + elem "info_child" + type = CHILD + pos = 0,0 size = 640x475 anchor1 = 0,0 anchor2 = 100,100 saved-params = "splitter" + splitter = 40 + background-color = #202020 left = "statwindow" right = "outputwindow" is-vert = false +window "input_buttons" + elem "input_buttons_main" + type = MAIN + pos = 0,0 + size = 640x475 + anchor1 = 0,0 + anchor2 = 100,100 + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true + elem "input_buttons_child" + type = CHILD + pos = 0,0 + size = 640x475 + anchor1 = 0,0 + anchor2 = 100,100 + background-color = #ffc41f + saved-params = "splitter" + left = "inputwindow" + right = "inputbuttons" + is-vert = true + splitter = 70 + show-splitter = false + window "outputwindow" elem "outputwindow" type = MAIN @@ -175,19 +222,14 @@ window "outputwindow" anchor2 = -1,-1 saved-params = "pos;size;is-minimized;is-maximized" is-pane = true - elem "output_input_child" + elem "output_selector_screen" type = CHILD - pos = 0,0 size = 640x475 anchor1 = 0,0 anchor2 = 100,100 - background-color = #ffc41f saved-params = "splitter" + background-color = #ffc41f left = "output_selector" - right = "input_and_buttons" - is-vert = false - splitter = 96 - show-splitter = false window "output_selector" elem "output_selector" @@ -207,27 +249,6 @@ window "output_selector" saved-params = "splitter" left = "output_legacy" is-vert = false - -window "input_and_buttons" - elem "input_and_buttons" - type = MAIN - pos = 291,0 - size = 640x20 - anchor1 = -1,-1 - anchor2 = -1,-1 - saved-params = "pos;size;is-minimized;is-maximized" - is-pane = true - elem "input_buttons_child" - type = CHILD - pos = 0,0 - size = 640x20 - anchor1 = 0,0 - anchor2 = 100,100 - background-color = #ffc41f - saved-params = "splitter" - left = "inputwindow" - right = "inputbuttons" - is-vert = true splitter = 80 show-splitter = false @@ -235,16 +256,16 @@ window "inputwindow" elem "inputwindow" type = MAIN pos = 575,0 - size = 520x25 - anchor1 = -1,-1 - anchor2 = -1,-1 + size = 480x25 + anchor1 = 0,0 + anchor2 = 70,100 background-color = none saved-params = "pos;size;is-minimized;is-maximized" is-pane = true elem "input" type = INPUT pos = 0,0 - size = 520x20 + size = 480x20 anchor1 = 0,0 anchor2 = 100,100 is-default = true @@ -256,8 +277,8 @@ window "inputbuttons" elem "inputbuttons" type = MAIN pos = 291,0 - size = 120x25 - anchor1 = 0,0 + size = 160x25 + anchor1 = 70,0 anchor2 = 100,100 saved-params = "pos;size;is-minimized;is-maximized" is-pane = true @@ -266,38 +287,51 @@ window "inputbuttons" pos = 0,0 size = 40x20 anchor1 = 0,0 - anchor2 = 33,100 + anchor2 = 25,100 font-size = 4 border = line saved-params = "is-checked" text = "Say" - command = ".winset \"saybutton.is-checked=true ? input.command=\"!say \\\"\" : input.command=\"\"saybutton.is-checked=true ? mebutton.is-checked=false\"\"saybutton.is-checked=true ? oocbutton.is-checked=false\"" + command = ".winset \"saybutton.is-checked=true ? input.command=\"!say \\\"\" : input.command=\"\"saybutton.is-checked=true ? mebutton.is-checked=false\"\"saybutton.is-checked=true ? oocbutton.is-checked=false\"\"saybutton.is-checked=true ? whisperbutton.is-checked=false\"" + is-flat = true + button-type = pushbox + elem "whisperbutton" + type = BUTTON + pos = 40,0 + size = 40x20 + anchor1 = 25,0 + anchor2 = 50,100 + font-size = 4 + border = line + saved-params = "is-checked" + text = "Whisper" + command = ".winset \"whisperbutton.is-checked=true ? input.command=\"!say \\\"#\" : input.command=\"\"whisperbutton.is-checked=false ? saybutton.is-checked=false\"\"whisperbutton.is-checked=true ? mebutton.is-checked=false\"\"whisperbutton.is-checked=true ? oocbutton.is-checked=false\"" is-flat = true button-type = pushbox elem "mebutton" type = BUTTON - pos = 40,0 + pos = 80,0 size = 40x20 - anchor1 = 33,0 - anchor2 = 66,100 + anchor1 = 50,0 + anchor2 = 75,100 font-size = 4 border = line saved-params = "is-checked" text = "Me" - command = ".winset \"mebutton.is-checked=true ? input.command=\"!me \\\"\" : input.command=\"\"mebutton.is-checked=true ? saybutton.is-checked=false\"\"mebutton.is-checked=true ? oocbutton.is-checked=false\"" + command = ".winset \"mebutton.is-checked=true ? input.command=\"!me \\\"\" : input.command=\"\"mebutton.is-checked=true ? saybutton.is-checked=false\"\"mebutton.is-checked=true ? oocbutton.is-checked=false\"\"mebutton.is-checked=true ? whisperbutton.is-checked=false\"" is-flat = true button-type = pushbox elem "oocbutton" type = BUTTON - pos = 80,0 + pos = 120,0 size = 40x20 - anchor1 = 66,0 + anchor1 = 75,0 anchor2 = 100,100 font-size = 4 border = line saved-params = "is-checked" text = "OOC" - command = ".winset \"oocbutton.is-checked=true ? input.command=\"!ooc \\\"\" : input.command=\"\"oocbutton.is-checked=true ? mebutton.is-checked=false\"\"oocbutton.is-checked=true ? saybutton.is-checked=false\"" + command = ".winset \"oocbutton.is-checked=true ? input.command=\"!ooc \\\"\" : input.command=\"\"oocbutton.is-checked=true ? mebutton.is-checked=false\"\"oocbutton.is-checked=true ? saybutton.is-checked=false\"\"oocbutton.is-checked=true ? whisperbutton.is-checked=false\"" is-flat = true button-type = pushbox diff --git a/tgstation.dme b/tgstation.dme index 7b10ea3d1e3..06086dbe517 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4348,6 +4348,7 @@ #include "code\modules\emote_panel\emote_panel.dm" #include "code\modules\error_handler\error_handler.dm" #include "code\modules\error_handler\error_viewer.dm" +#include "code\modules\escape_menu\admin_page.dm" #include "code\modules\escape_menu\details.dm" #include "code\modules\escape_menu\dimmer.dm" #include "code\modules\escape_menu\escape_menu.dm" diff --git a/tgui/packages/tgui-panel/settings/scaling.ts b/tgui/packages/tgui-panel/settings/scaling.ts index bd1b5250012..77cc5f831ba 100644 --- a/tgui/packages/tgui-panel/settings/scaling.ts +++ b/tgui/packages/tgui-panel/settings/scaling.ts @@ -11,6 +11,7 @@ const ELEMENTS_TO_ADJUST = [ 'inputbuttons.saybutton', 'inputbuttons.mebutton', 'inputbuttons.oocbutton', + 'inputbuttons.whisperbutton', 'mapwindow.status_bar', ]; @@ -33,8 +34,8 @@ export async function setDisplayScaling() { const PANE_SPLITTERS = { info_button_child: 2, - input_buttons_child: 80, - output_input_child: 96, + input_buttons_child: 70, + info_split: 97.5, }; export function setEditPaneSplitters(editing: boolean) { diff --git a/tgui/packages/tgui-panel/settings/themes.ts b/tgui/packages/tgui-panel/settings/themes.ts index e94aaf7be3a..1bfd05800cb 100644 --- a/tgui/packages/tgui-panel/settings/themes.ts +++ b/tgui/packages/tgui-panel/settings/themes.ts @@ -68,6 +68,8 @@ export function setClientTheme(name): void | Promise { 'saybutton.text-color': themeColor.TEXT, 'oocbutton.background-color': themeColor.BG_BASE, 'oocbutton.text-color': themeColor.TEXT, + 'whisperbutton.background-color': themeColor.BG_BASE, + 'whisperbutton.text-color': themeColor.TEXT, 'mebutton.background-color': themeColor.BG_BASE, 'mebutton.text-color': themeColor.TEXT, 'asset_cache_browser.background-color': themeColor.BG_BASE, diff --git a/tgui/packages/tgui-say/ChannelIterator.test.ts b/tgui/packages/tgui-say/ChannelIterator.test.ts index b57f0d0df74..11d949b7fc9 100644 --- a/tgui/packages/tgui-say/ChannelIterator.test.ts +++ b/tgui/packages/tgui-say/ChannelIterator.test.ts @@ -14,6 +14,7 @@ describe('ChannelIterator', () => { expect(channelIterator.next()).toBe('Radio'); expect(channelIterator.next()).toBe('Me'); expect(channelIterator.next()).toBe('OOC'); + expect(channelIterator.next()).toBe('Pray'); expect(channelIterator.next()).toBe('Say'); // Admin is blacklisted so it should be skipped }); diff --git a/tgui/packages/tgui-say/ChannelIterator.ts b/tgui/packages/tgui-say/ChannelIterator.ts index 5d73730e51a..d4b6380be7d 100644 --- a/tgui/packages/tgui-say/ChannelIterator.ts +++ b/tgui/packages/tgui-say/ChannelIterator.ts @@ -1,4 +1,4 @@ -export type Channel = 'Say' | 'Radio' | 'Me' | 'OOC' | 'Admin'; +export type Channel = 'Say' | 'Radio' | 'Me' | 'OOC' | 'Admin' | 'Pray'; /** * ### ChannelIterator @@ -8,9 +8,9 @@ export type Channel = 'Say' | 'Radio' | 'Me' | 'OOC' | 'Admin'; */ export class ChannelIterator { private index: number = 0; - private readonly channels: Channel[] = ['Say', 'Radio', 'Me', 'OOC', 'Admin']; + private readonly channels: Channel[] = ['Say', 'Radio', 'Me', 'OOC', 'Admin', 'Pray']; private readonly blacklist: Channel[] = ['Admin']; - private readonly quiet: Channel[] = ['OOC', 'Admin']; + private readonly quiet: Channel[] = ['OOC', 'Admin', 'Pray']; public next(): Channel { if (this.blacklist.includes(this.channels[this.index])) { diff --git a/tgui/packages/tgui-say/styles/colors.scss b/tgui/packages/tgui-say/styles/colors.scss index 0ba363660bb..42a7144b9e2 100644 --- a/tgui/packages/tgui-say/styles/colors.scss +++ b/tgui/packages/tgui-say/styles/colors.scss @@ -20,6 +20,7 @@ $_channel_map: ( 'Med': hsl(202, 83.6%, 64.1%), 'OOC': hsl(47.9, 100%, 40%), 'Ent': hsl(176.1, 20%, 45.1%), + 'Pray': hsl(214, 86%, 30%), 'Radio': hsl(132.8, 74.4%, 45.9%), 'Say': hsl(213.6, 37.9%, 74.1%), 'Sci': hsl(271.6, 91.7%, 76.5%),