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%),