diff --git a/code/datums/emote.dm b/code/datums/emote.dm
index 3fd59a10f38d..aedc8524a2b6 100644
--- a/code/datums/emote.dm
+++ b/code/datums/emote.dm
@@ -288,7 +288,7 @@
* * user - The user of the emote.
* * text - The text of the emote.
*/
-/datum/emote/proc/runechat_emote(mob/user, text)
+/proc/runechat_emote(atom/user, text)
var/runechat_text = text
if(length(text) > 100)
runechat_text = "[copytext(text, 1, 101)]..."
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 9d33e71059b7..95735505f540 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1175,6 +1175,13 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flick_overlay), I, speech_bubble_hearers, 30)
+/atom/proc/atom_emote(emote)
+ if(!emote)
+ return
+ visible_message("[src] [emote]", "You hear how something [emote]")
+
+ runechat_emote(src, emote)
+
/atom/proc/speech_bubble(bubble_state = "", bubble_loc = src, list/bubble_recipients = list())
return
diff --git a/code/modules/buildmode/submodes/say.dm b/code/modules/buildmode/submodes/say.dm
new file mode 100644
index 000000000000..62c4456ebc6b
--- /dev/null
+++ b/code/modules/buildmode/submodes/say.dm
@@ -0,0 +1,36 @@
+/datum/buildmode_mode/say
+ key = "say"
+
+/datum/buildmode_mode/say/show_help(mob/user)
+ to_chat(user, "***********************************************************")
+ to_chat(user, "Left Mouse Button = Say")
+ to_chat(user, "Right Mouse Button = Emote")
+ to_chat(user, "***********************************************************")
+
+/datum/buildmode_mode/say/handle_click(mob/user, params, atom/object)
+ if(ismob(object))
+ var/mob/target = object
+ if(!isnull(target.ckey))
+ alert("This cannot be used on mobs with a ckey. Use Forcesay in player panel instead.")
+ return
+
+ var/list/pa = params2list(params)
+ var/left_click = pa.Find("left")
+ var/right_click = pa.Find("right")
+
+ if(left_click)
+ var/say = tgui_input_text(user, "What should [object] say?", "Say what?")
+ if(isnull(say))
+ return
+ log_admin("Build Mode: [key_name(user)] made [object] at ([object.x],[object.y],[object.z] say [say].")
+ message_admins("Build Mode: [key_name(user)] made [object] at ([object.x],[object.y],[object.z] say [say].")
+ user.create_log(MISC_LOG, "Made [object] at ([object.x],[object.y],[object.z] say [say].")
+ object.atom_say(say)
+ else if(right_click)
+ var/emote = tgui_input_text(user, "What should [object] do?", "Emote what?")
+ if(isnull(emote))
+ return
+ log_admin("Build Mode: [key_name(user)] made [object] at ([object.x],[object.y],[object.z] emote *[emote].")
+ message_admins("Build Mode: [key_name(user)] made [object] at ([object.x],[object.y],[object.z] emote *[emote].")
+ user.create_log(MISC_LOG, "Made [object] at ([object.x],[object.y],[object.z] emote *[emote].")
+ object.atom_emote(emote)
diff --git a/icons/misc/buildmode.dmi b/icons/misc/buildmode.dmi
index 80c9d404a10b..fac68ff7981c 100644
Binary files a/icons/misc/buildmode.dmi and b/icons/misc/buildmode.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 111f44183ed9..e5ba213e52d3 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1717,6 +1717,7 @@
#include "code\modules\buildmode\submodes\mapgen.dm"
#include "code\modules\buildmode\submodes\offer.dm"
#include "code\modules\buildmode\submodes\save.dm"
+#include "code\modules\buildmode\submodes\say.dm"
#include "code\modules\buildmode\submodes\throwing.dm"
#include "code\modules\buildmode\submodes\tilt.dm"
#include "code\modules\buildmode\submodes\variable_edit.dm"