diff --git a/code/__DEFINES/~skyrat_defines/logging.dm b/code/__DEFINES/~skyrat_defines/logging.dm
new file mode 100644
index 00000000000..d90eb1db421
--- /dev/null
+++ b/code/__DEFINES/~skyrat_defines/logging.dm
@@ -0,0 +1 @@
+#define LOG_SUBTLER (1 << 20)
diff --git a/code/__DEFINES/~skyrat_defines/preferences.dm b/code/__DEFINES/~skyrat_defines/preferences.dm
new file mode 100644
index 00000000000..341904615ab
--- /dev/null
+++ b/code/__DEFINES/~skyrat_defines/preferences.dm
@@ -0,0 +1,5 @@
+//Skyrat toggles
+#define CHAT_LOOC (1<<0)
+#define CHAT_LOOC_ADMIN (1<<1)
+
+#define TOGGLES_DEFAULT_SKYRAT (CHAT_LOOC|CHAT_LOOC_ADMIN)
diff --git a/modular_skyrat/master_files/code/_globalvars/configuration.dm b/modular_skyrat/master_files/code/_globalvars/configuration.dm
new file mode 100644
index 00000000000..6322a74ec1a
--- /dev/null
+++ b/modular_skyrat/master_files/code/_globalvars/configuration.dm
@@ -0,0 +1,2 @@
+//LOOC Module
+GLOBAL_VAR_INIT(looc_allowed, TRUE)
diff --git a/modular_skyrat/master_files/readme.md b/modular_skyrat/master_files/readme.md
index 7aed32a6cb2..ca5212b4915 100644
--- a/modular_skyrat/master_files/readme.md
+++ b/modular_skyrat/master_files/readme.md
@@ -14,3 +14,7 @@ MASTER CODE FILES
- /master_files/code/modules/power/lighting.dm
- /master_files/code/modules/clothing/non_anthro_clothes.dm > PLEASE USE THIS TO LOG ANY CLOTHES THAT DO NOT NEED ANTHRO VARIANTS.
- /master_files/code/modules/clothing/anthro_clothes.dm > PLEASE USE THIS TO LOG ANY CLOTHES THAT DO NEED ANTHRO VARIANTS.
+
+MASTER GLOBAL VARS
+- modular_skyrat/master_files/code/_globalvars/configuration.dm > GLOBAL_VAR_INIT(looc_allowed, TRUE)
+
diff --git a/modular_skyrat/modules/customization/modules/client/preferences.dm b/modular_skyrat/modules/customization/modules/client/preferences.dm
index b69455d867f..56108e6d5d8 100644
--- a/modular_skyrat/modules/customization/modules/client/preferences.dm
+++ b/modular_skyrat/modules/customization/modules/client/preferences.dm
@@ -45,6 +45,7 @@
var/toggles = TOGGLES_DEFAULT
var/db_flags
var/chat_toggles = TOGGLES_DEFAULT_CHAT
+ var/skyrat_toggles = TOGGLES_DEFAULT_SKYRAT
var/ghost_form = "ghost"
var/ghost_orbit = GHOST_ORBIT_CIRCLE
var/ghost_accs = GHOST_ACCS_DEFAULT_OPTION
@@ -754,7 +755,6 @@
loadout_button_class = "class='linkOff'"
else //We can buy it
loadout_button_class = "href='?_src_=prefs;task=change_loadout;item=[path]'"
-
dat += "
"
dat += "| [LI.name] | "
dat += "[customization_button] | "
diff --git a/modular_skyrat/modules/verbs/code/modules/client/preferences_toggles.dm b/modular_skyrat/modules/verbs/code/modules/client/preferences_toggles.dm
new file mode 100644
index 00000000000..7f0b441b23b
--- /dev/null
+++ b/modular_skyrat/modules/verbs/code/modules/client/preferences_toggles.dm
@@ -0,0 +1,9 @@
+
+/client/verb/listen_looc()
+ set name = "Show/Hide LOOC"
+ set category = "Preferences"
+ set desc = "Toggles seeing LocalOutOfCharacter chat"
+ usr.client.prefs.skyrat_toggles ^= CHAT_LOOC
+ usr.client.prefs.save_preferences()
+ to_chat(usr, "You will [(usr.client.prefs.skyrat_toggles & CHAT_LOOC) ? "now" : "no longer"] see messages on the LOOC channel.")
+ SSblackbox.record_feedback("nested tally", "preferences_verb", 1, list("Toggle Seeing LOOC", "[usr.client.prefs.skyrat_toggles & CHAT_LOOC ? "Enabled" : "Disabled"]"))
diff --git a/modular_skyrat/modules/verbs/code/modules/client/verbs/looc.dm b/modular_skyrat/modules/verbs/code/modules/client/verbs/looc.dm
new file mode 100644
index 00000000000..bbfb58af2f7
--- /dev/null
+++ b/modular_skyrat/modules/verbs/code/modules/client/verbs/looc.dm
@@ -0,0 +1,67 @@
+/client/verb/looc(msg as text)
+ set name = "LOOC"
+ set desc = "Local OOC, seen only by those in view."
+ set category = "OOC"
+
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, " Speech is currently admin-disabled.")
+ return
+
+ if(!mob)
+ return
+
+ msg = copytext_char(sanitize(msg), 1, MAX_MESSAGE_LEN)
+ if(!msg)
+ return
+
+ if(!(prefs.skyrat_toggles & CHAT_LOOC))
+ to_chat(src, " You have LOOC muted.")
+ return
+ if(is_banned_from(mob, "OOC"))
+ to_chat(src, "You have been banned from OOC.")
+ return
+
+ if(!holder)
+ if(!GLOB.looc_allowed)
+ to_chat(src, " LOOC is globally muted")
+ return
+ if(prefs.muted & MUTE_OOC)
+ to_chat(src, " You cannot use OOC (muted).")
+ return
+ if(handle_spam_prevention(msg,MUTE_OOC))
+ return
+ if(findtext(msg, "byond://"))
+ to_chat(src, "Advertising other servers is not allowed.")
+ log_admin("[key_name(src)] has attempted to advertise in LOOC: [msg]")
+ return
+ if(mob.stat)
+ to_chat(src, "You cannot use LOOC while unconscious or dead.") //Skyrat change
+ return
+ if(istype(mob, /mob/dead))
+ to_chat(src, "You cannot use LOOC while ghosting.")
+ return
+
+ msg = emoji_parse(msg)
+
+ mob.log_talk(msg,LOG_OOC, tag="(LOOC)")
+
+ var/list/heard = get_hearers_in_view(7, get_top_level_mob(src.mob))
+ for(var/mob/M in heard)
+ if(!M.client)
+ continue
+ var/client/C = M.client
+ if (C in GLOB.admins)
+ continue //they are handled after that
+
+ if (isobserver(M))
+ continue //Also handled later.
+
+ if(C.prefs.skyrat_toggles & CHAT_LOOC)
+ to_chat(C, "LOOC: [src.mob.name]: [msg]")
+
+ for(var/client/C in GLOB.admins)
+ if(C.prefs.skyrat_toggles & CHAT_LOOC)
+ if (C.mob in heard)
+ to_chat(C, "[ADMIN_FLW(usr)] LOOC: [src.key]/[src.mob.name]: [msg]")
+ else if (!(C.prefs.skyrat_toggles & CHAT_LOOC_ADMIN))
+ to_chat(C, "[ADMIN_FLW(usr)] (R)LOOC: [src.key]/[src.mob.name]: [msg]")
diff --git a/modular_skyrat/modules/verbs/code/modules/mob/say.dm b/modular_skyrat/modules/verbs/code/modules/mob/say.dm
new file mode 100644
index 00000000000..6aa3918a0a3
--- /dev/null
+++ b/modular_skyrat/modules/verbs/code/modules/mob/say.dm
@@ -0,0 +1,23 @@
+/mob/proc/get_top_level_mob()
+ if(istype(src.loc,/mob)&&src.loc!=src)
+ var/mob/M=src.loc
+ return M.get_top_level_mob()
+ return src
+
+/proc/get_top_level_mob(var/mob/S)
+ if(istype(S.loc,/mob)&&S.loc!=S)
+ var/mob/M=S.loc
+ return M.get_top_level_mob()
+ return S
+
+#define ENCODE_HTML_EPHASIS(input, char, html, varname) \
+ var/static/regex/##varname = regex("[char]{2}(.+?)[char]{2}", "g");\
+ input = varname.Replace_char(input, "<[html]>$1[html]>")
+
+/atom/movable/proc/say_emphasis(input)
+ ENCODE_HTML_EPHASIS(input, "\\|", "i", italics)
+ ENCODE_HTML_EPHASIS(input, "\\+", "b", bold)
+ ENCODE_HTML_EPHASIS(input, "_", "u", underline)
+ return input
+
+#undef ENCODE_HTML_EPHASIS
diff --git a/modular_skyrat/modules/verbs/code/modules/mob/subtle.dm b/modular_skyrat/modules/verbs/code/modules/mob/subtle.dm
new file mode 100644
index 00000000000..88f0d02423b
--- /dev/null
+++ b/modular_skyrat/modules/verbs/code/modules/mob/subtle.dm
@@ -0,0 +1,152 @@
+/datum/emote/living/subtle
+ key = "subtle"
+ key_third_person = "subtle"
+ message = null
+ mob_type_blacklist_typecache = list(/mob/living/brain)
+
+/datum/emote/living/subtle/proc/check_invalid(mob/user, input)
+ /* TO DO
+ if(stop_bad_mime.Find(input, 1, 1))
+ to_chat(user, "Invalid emote.")
+ return TRUE
+ */
+ return FALSE
+
+/datum/emote/living/subtle/run_emote(mob/user, params, type_override = null)
+ if(is_banned_from(user, "emote"))
+ to_chat(user, "You cannot send subtle emotes (banned).")
+ return FALSE
+ else if(user.client && user.client.prefs.muted & MUTE_IC)
+ to_chat(user, "You cannot send IC messages (muted).")
+ return FALSE
+ else if(!params)
+ var/subtle_emote = stripped_multiline_input(user, "Choose an emote to display.", "Subtle", null, MAX_MESSAGE_LEN)
+ if(subtle_emote && !check_invalid(user, subtle_emote))
+ var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
+ switch(type)
+ if("Visible")
+ emote_type = EMOTE_VISIBLE
+ if("Hearable")
+ emote_type = EMOTE_AUDIBLE
+ else
+ alert("Unable to use this emote, must be either hearable or visible.")
+ return
+ message = subtle_emote
+ else
+ return FALSE
+ else
+ message = params
+ if(type_override)
+ emote_type = type_override
+ . = TRUE
+ if(!can_run_emote(user))
+ return FALSE
+
+ user.log_message(message, LOG_EMOTE)
+ message = "[user] " + "[user.say_emphasis(message)]"
+
+ for(var/mob/M in GLOB.dead_mob_list)
+ if(!M.client || isnewplayer(M))
+ continue
+ var/T = get_turf(src)
+ if(M.stat == DEAD && M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT) && !(M in viewers(T, null)))
+ M.show_message(message)
+
+ if(emote_type == EMOTE_AUDIBLE)
+ user.audible_message(message=message,hearing_distance=1)
+ else
+ user.visible_message(message=message,self_message=message,vision_distance=1)
+
+
+///////////////// SUBTLE 2: NO GHOST BOOGALOO
+
+/datum/emote/living/subtler
+ key = "subtler"
+ key_third_person = "subtler"
+ message = null
+ mob_type_blacklist_typecache = list(/mob/living/brain)
+
+
+/datum/emote/living/subtler/proc/check_invalid(mob/user, input)
+ /* TO DO
+ if(stop_bad_mime.Find(input, 1, 1))
+ to_chat(user, "Invalid emote.")
+ return TRUE
+ */
+ return FALSE
+
+/datum/emote/living/subtler/run_emote(mob/user, params, type_override = null)
+ if(is_banned_from(user, "emote"))
+ to_chat(user, "You cannot send subtle emotes (banned).")
+ return FALSE
+ else if(user.client && user.client.prefs.muted & MUTE_IC)
+ to_chat(user, "You cannot send IC messages (muted).")
+ return FALSE
+ else if(!params)
+ var/subtle_emote = stripped_multiline_input(user, "Choose an emote to display.", "Subtler" , null, MAX_MESSAGE_LEN)
+ if(subtle_emote && !check_invalid(user, subtle_emote))
+ var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable")
+ switch(type)
+ if("Visible")
+ emote_type = EMOTE_VISIBLE
+ if("Hearable")
+ emote_type = EMOTE_AUDIBLE
+ else
+ alert("Unable to use this emote, must be either hearable or visible.")
+ return
+ message = subtle_emote
+ else
+ return FALSE
+ else
+ message = params
+ if(type_override)
+ emote_type = type_override
+ . = TRUE
+ if(!can_run_emote(user))
+ return FALSE
+
+ user.log_message(message, LOG_SUBTLER)
+ message = "[user] " + "[user.say_emphasis(message)]"
+
+ if(emote_type == EMOTE_AUDIBLE)
+ user.audible_message_subtler(message=message,hearing_distance=1, ignored_mobs = GLOB.dead_mob_list)
+ else
+ user.visible_message(message=message,self_message=message,vision_distance=1, ignored_mobs = GLOB.dead_mob_list)
+
+///////////////// VERB CODE
+/mob/living/proc/subtle_keybind()
+ var/message = input(src, "", "subtle") as text|null
+ if(!length(message))
+ return
+ return subtle(message)
+
+/mob/living/verb/subtle()
+ set name = "Subtle"
+ set category = "IC"
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, "Speech is currently admin-disabled.")
+ return
+ usr.emote("subtle")
+
+///////////////// VERB CODE 2
+/mob/living/verb/subtler()
+ set name = "Subtler Anti-Ghost"
+ set category = "IC"
+ if(GLOB.say_disabled) //This is here to try to identify lag problems
+ to_chat(usr, "Speech is currently admin-disabled.")
+ return
+ usr.emote("subtler")
+
+//This is bad code.
+/atom/proc/audible_message_subtler(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, self_message, audible_message_flags = NONE)
+ var/list/hearers = get_hearers_in_view(hearing_distance, src)
+ if(self_message)
+ hearers -= src
+ hearers -= ignored_mobs
+ var/raw_msg = message
+ if(audible_message_flags & EMOTE_MESSAGE)
+ message = "[src] [message]"
+ for(var/mob/M in hearers)
+ if(audible_message_flags & EMOTE_MESSAGE && runechat_prefs_check(M, audible_message_flags) && M.can_hear())
+ M.create_chat_message(src, raw_message = raw_msg, runechat_flags = audible_message_flags)
+ M.show_message(message, MSG_AUDIBLE, deaf_message, MSG_VISUAL)
diff --git a/modular_skyrat/modules/verbs/readme.md b/modular_skyrat/modules/verbs/readme.md
new file mode 100644
index 00000000000..d68fbacaf17
--- /dev/null
+++ b/modular_skyrat/modules/verbs/readme.md
@@ -0,0 +1,30 @@
+https://github.com/Skyrat-SS13/Skyrat-tg/pull/872
+
+## Title: More verbs and subtler.
+
+MODULE ID: VERBS
+
+### Description:
+
+Adds a few emotes and verbs for players to use, such as LOOC, subtle.
+
+### TG Proc Changes:
+
+- N/A
+
+### Defines:
+
+- #define CHAT_LOOC (1<<12)
+- #define CHAT_LOOC_ADMIN (1<<13)
+- #define LOG_SUBTLER (1 << 20)
+
+### Master file additions
+
+- D:\Documents\Github\SS13\Skyrat-tg\modular_skyrat\master_files\code\_globalvars\configuration.dm
+
+### Included files that are not contained in this module:
+
+- N/A
+
+### Credits:
+Gandalf2k15 - porting and refactoring
diff --git a/tgstation.dme b/tgstation.dme
index 11a9c96efb3..72335dc0158 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -131,7 +131,9 @@
#include "code\__DEFINES\research\anomalies.dm"
#include "code\__DEFINES\~skyrat_defines\blueshield.dm"
#include "code\__DEFINES\~skyrat_defines\DNA.dm"
+#include "code\__DEFINES\~skyrat_defines\logging.dm"
#include "code\__DEFINES\~skyrat_defines\obj_flags.dm"
+#include "code\__DEFINES\~skyrat_defines\preferences.dm"
#include "code\__DEFINES\~skyrat_defines\robot_defines.dm"
#include "code\__DEFINES\~skyrat_defines\say.dm"
#include "code\__DEFINES\~skyrat_defines\signals.dm"
@@ -3234,6 +3236,7 @@
#include "interface\menu.dm"
#include "interface\stylesheet.dm"
#include "interface\skin.dmf"
+#include "modular_skyrat\master_files\code\_globalvars\configuration.dm"
#include "modular_skyrat\master_files\code\modules\clothing\anthro_clothes.dm"
#include "modular_skyrat\master_files\code\modules\clothing\non_anthro_clothes.dm"
#include "modular_skyrat\master_files\code\modules\power\lighting.dm"
@@ -3385,4 +3388,8 @@
#include "modular_skyrat\modules\modular_weapons\code\modules\projectiles\projectile\bullets\modular_projectiles.dm"
#include "modular_skyrat\modules\modular_weapons\code\modules\research\designs\autolathe_designs.dm"
#include "modular_skyrat\modules\typing_indicator\code\mob.dm"
+#include "modular_skyrat\modules\verbs\code\modules\client\preferences_toggles.dm"
+#include "modular_skyrat\modules\verbs\code\modules\client\verbs\looc.dm"
+#include "modular_skyrat\modules\verbs\code\modules\mob\say.dm"
+#include "modular_skyrat\modules\verbs\code\modules\mob\subtle.dm"
// END_INCLUDE