From a52657cc5a9f43f1ad8ef4ea8ba8fe0d72acdbfa Mon Sep 17 00:00:00 2001
From: "FunnyMan3595 (Charlie Nolan)" <funnyman3595@gmail.com>
Date: Sat, 4 Jan 2025 18:33:40 +0000
Subject: [PATCH 1/5] Implement atom_emote

---
 code/datums/emote.dm | 2 +-
 code/game/atoms.dm   | 8 ++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/code/datums/emote.dm b/code/datums/emote.dm
index 3fd59a10f38d0..aedc8524a2b63 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 9d33e71059b7e..75548318b9500 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1175,6 +1175,14 @@ 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
+	for(var/mob/M as anything in get_mobs_in_view(7, src))
+		M.show_message("<span class='game emote'><span class='name'>[src]</span> [emote]</span>", EMOTE_VISIBLE, null, MESSAGE_TYPE_LOCALCHAT)
+
+	runechat_emote(src, emote)
+
 /atom/proc/speech_bubble(bubble_state = "", bubble_loc = src, list/bubble_recipients = list())
 	return
 

From 7d802c115c57e96e813cb81c85b36d3471cd1f46 Mon Sep 17 00:00:00 2001
From: "FunnyMan3595 (Charlie Nolan)" <funnyman3595@gmail.com>
Date: Sat, 4 Jan 2025 10:43:53 -0800
Subject: [PATCH 2/5] Buildmode say icon

---
 icons/misc/buildmode.dmi | Bin 2009 -> 2027 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/icons/misc/buildmode.dmi b/icons/misc/buildmode.dmi
index 80c9d404a10b2fc712b918d2901352145548a832..fac68ff7981cb9efc8b0881b294e6b49cfb61c77 100644
GIT binary patch
delta 1822
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
M07*qoM6N<$f>!~3TL1t6

delta 1803
zcmV+m2lV*s57`fpTLJZvTtNfZ?_ZIiPJb2^M5-4lL3iM5)QiNZDVuCkm`vb)k<vkX
zMn7+zf0u>NtGWH3XEE+DAWW^|iKHQG3vf&Rw*ar0T>&1U!;-kkaV*Kop+?6=9s#l!
zd8a-0>edv@<)*=q<JW3`+}-|+D-WDQ=j+0JMF0Q>Xh}ptRA_<inopMGGz`YW4S#@Q
z*mHz>tY*m(SmZr#S-}a2w=9fxY%Ix6WXHCge=x)AbkB5s9aqP{$Z|f}HU0Emc6|R$
zuD`vir`ONf@xEJ6ueZG5>wUMLUO&v@_~m`Ko?buxzO2Wezr7pU`u_PsTL8~`dVP{t
z{Po??0R8j11~<<JNC$#N9N2@Jj(<IBp3k*q;Zctg7<Yhx+s@_yL5#r|flclGLj*1<
z^9+IA+WSWc%qHD)1OU$wU`wFy*<2*BtbN|z$3(!N=Lrnp;pm?8%Z<PogYBJj9fGpQ
zJ57HTQ1h$pytme3d+&XRK)dG}0S=)<1l1TdW3T{y_hN8p?#VTEpJ(4r9)BE}dkSqg
z*~x>e1pNMI2)3Bm&TM*t0G|W=e%F~zuMi{z+j*jyIIvF<%yB+-@rhP-2|ODPyNE(#
zUR&t8iYqb5?m#eJ@*bjbx>x@T*70fc`?!6-`wxE92WRVp&CieNedf0^dn*0>kgjBI
zEAyw)&yVQsNE&$V;wM@#6o1wNIg3aj{rrgD5d^wz_6?rG(RcVQ6J&mVK<^1cfGn&8
z!4ZXjfxyORa^~j;^p1eSLkR4X5<z?>=YC$-djdL12vvgI&+EE2ittFIEOb1NLGI@V
zGyr~6atNZ002XW!zTzm#{k*PmG#R!Il3<NNPB@i*Ue~BB4=pjOwtrES$7m}3ysqm6
zEf+GCeqPsA0-I$rr3QX&1oNEtxTC8C!i8Y#z>8_H#z6RaU1RrYAY}xb6AU>(Up7_x
zxu4f{H4h{K%mD)2N|5_`U03F!k{|>PQ&|$MeqPrq!R*l2Z3MZWAJ7^BU<kx0%KiL+
zt`Ri#RQmZ5T_I@dseknIBf1}h9YOBrhjcmyRwbu;MWg8>G5DwtH1qqoeLwmJtzaq7
ze}(nI=Ujg=`v<4>=&EB!o6WnX=LIg~t(jc-`4cN#kQ8{~RijUuN<V*s2vYr!-p|^t
z1eqH?u|AX#K-3cp+d(GC{QQ}iFalNySv}!S69nH3K!!WsbAN~c;u+41!O>N?gE4R}
zzN1=&Mju53i3u`4Pxmyu3Z5X|QygGEv<coc5{4HU0U=N!oqUvy>)G`@AQrPdgR!^q
zNTY-Z1Yz)TFbe`+Fi%zHZd712>{b_h8*s4OD*;DM#7OS5*>!C``69Fgz=oL#fNyY<
zpb{goQ)trKJb$guvoEsY4%*fC><Q?uqvK4Y25p;_qfA!%G=$Rr0$2KICyj$f40b){
z0zj@^WUj-_>jh$^Z#~^pzhtARy*3fv0Qe5ER^dgB=1T(XkmJ>c(Uo0C?pdx?h$_?U
z2o^NM;RlTFwn9OWoL};?6#~G1ot#ZMiNzf-1;NqTbALZK`6Z_Fn%Q|C9PM$T8GsPP
z6HVs9MFL3m!xqDMfdl)=9i0FWLF5JPt+n?L4(LC&8t(6H6_Nn%aTRsVzT%@kc%nWy
zY~RaY+^xUB`rxyoi}oM&!O&_8`Z`bloqQhjG_AfHddQkn>p@j#2xMN(y5eQYQrPzX
zK%uc9>VNDvd-7S{ub+?tFyPQ#juIqi+N^lk3Q7XI93g-uBLKfAAk$%G3;@PsP!PCA
zd(+#~*J7{;0#A1we6{@@c>wIZ>*rG*ELZZtD+H7RJvXh#q)$KtNYn!a;}_fPap-Iq
zNLW$CQN$y^NdRR<lh*&6J*Lz*p`sX@i%J5&#DDew?kK|Sv14-)W-=C8iGW@T0*9Ne
z)a$jfXM(sZr4p1qC<#adrh7rK3=)(*pdQl%C1L``tfLI5Ds`s`>O@$$on3wJ^<W)U
zVA}i17YR5o?D%YZl;D#7Ke&pI`am<kkK1>(L2+p3cZZ6owAU|C1Z5W_rM-Ru&EG5S
z^?wU!nW(haFQ8?j(tdz|KR`fhzqQ$L-@bdkM!+AL*w#&NC*Y4v*!q6)9R%nt(Hm7)
z-|r%jE5HAB42+AW!_b=C5CJ`MM@JEVYJxuAVo&CQA=d*90>>X-L1HsTkoA~Wc9&=(
zS_HtW^|UT}ieQdbv`YY7gPkIvf~P|eV|ZW(N6|@w_&K@(0yLhq(*#)z;I>f|Zf0Dr
z7|H`dF#k11z*CX0y61iSxW9wjYs<(5IFq^9e{e23KyYp@GFXN^_&mU^$pxNzqV4kF
tW`eKYRcQWRX|G@4aqIZB`F+~H{{yxcvyXp*0%`yN002ovPDHLkV1n$Cd07Ae


From 960985177d98b5e5830a7428ecd2be51dfab1d6d Mon Sep 17 00:00:00 2001
From: "FunnyMan3595 (Charlie Nolan)" <funnyman3595@gmail.com>
Date: Sat, 4 Jan 2025 19:00:56 +0000
Subject: [PATCH 3/5] Buildmode say

---
 code/modules/buildmode/submodes/say.dm | 26 ++++++++++++++++++++++++++
 paradise.dme                           |  1 +
 2 files changed, 27 insertions(+)
 create mode 100644 code/modules/buildmode/submodes/say.dm

diff --git a/code/modules/buildmode/submodes/say.dm b/code/modules/buildmode/submodes/say.dm
new file mode 100644
index 0000000000000..21bfb194182bb
--- /dev/null
+++ b/code/modules/buildmode/submodes/say.dm
@@ -0,0 +1,26 @@
+/datum/buildmode_mode/say
+	key = "say"
+
+/datum/buildmode_mode/say/show_help(mob/user)
+	to_chat(user, "<span class='notice'>***********************************************************</span>")
+	to_chat(user, "<span class='notice'>Left Mouse Button        = Say</span>")
+	to_chat(user, "<span class='notice'>Right Mouse Button       = Emote</span>")
+	to_chat(user, "<span class='notice'>***********************************************************</span>")
+
+/datum/buildmode_mode/say/handle_click(user, params, obj/object)
+	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].")
+		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].")
+		object.atom_emote(emote)
diff --git a/paradise.dme b/paradise.dme
index 111f44183ed96..e5ba213e52d36 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"

From 7b1a173a27870e4b6ce4cc0cb876a8f1c1eebefa Mon Sep 17 00:00:00 2001
From: "FunnyMan3595 (Charlie Nolan)" <funnyman3595@gmail.com>
Date: Sat, 4 Jan 2025 22:55:48 +0000
Subject: [PATCH 4/5] Better logging.

---
 code/modules/buildmode/submodes/say.dm | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/code/modules/buildmode/submodes/say.dm b/code/modules/buildmode/submodes/say.dm
index 21bfb194182bb..6d09056f18082 100644
--- a/code/modules/buildmode/submodes/say.dm
+++ b/code/modules/buildmode/submodes/say.dm
@@ -7,7 +7,13 @@
 	to_chat(user, "<span class='notice'>Right Mouse Button       = Emote</span>")
 	to_chat(user, "<span class='notice'>***********************************************************</span>")
 
-/datum/buildmode_mode/say/handle_click(user, params, obj/object)
+/datum/buildmode_mode/say/handle_click(mob/user, params, atom/object)
+	if(istype(object, /mob))
+		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")
@@ -17,10 +23,14 @@
 		if(isnull(say))
 			return
 		log_admin("Build Mode: [key_name(user)] made [object] at ([object.x],[object.y],[object.z] say [say].")
+		message_admins("<span class='notice'>Build Mode: [key_name(user)] made [object] at ([object.x],[object.y],[object.z] say [say].</span>")
+		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("<span class='notice'>Build Mode: [key_name(user)] made [object] at ([object.x],[object.y],[object.z] emote *[emote].</span>")
+		user.create_log(MISC_LOG, "Made [object] at ([object.x],[object.y],[object.z] emote *[emote].")
 		object.atom_emote(emote)

From 32eb3ba6cf3746d976c370cb6dfc8ecdbbcf970b Mon Sep 17 00:00:00 2001
From: Charlie Nolan <funnyman3595@gmail.com>
Date: Mon, 6 Jan 2025 16:04:48 -0800
Subject: [PATCH 5/5] Apply suggestions from code review

Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
Signed-off-by: Charlie Nolan <funnyman3595@gmail.com>
---
 code/game/atoms.dm                     | 3 +--
 code/modules/buildmode/submodes/say.dm | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 75548318b9500..95735505f540a 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1178,8 +1178,7 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
 /atom/proc/atom_emote(emote)
 	if(!emote)
 		return
-	for(var/mob/M as anything in get_mobs_in_view(7, src))
-		M.show_message("<span class='game emote'><span class='name'>[src]</span> [emote]</span>", EMOTE_VISIBLE, null, MESSAGE_TYPE_LOCALCHAT)
+	visible_message("<span class='game emote'><span class='name'>[src]</span> [emote]</span>", "<span class='game emote'>You hear how something [emote]</span>")
 
 	runechat_emote(src, emote)
 
diff --git a/code/modules/buildmode/submodes/say.dm b/code/modules/buildmode/submodes/say.dm
index 6d09056f18082..62c4456ebc6b6 100644
--- a/code/modules/buildmode/submodes/say.dm
+++ b/code/modules/buildmode/submodes/say.dm
@@ -8,7 +8,7 @@
 	to_chat(user, "<span class='notice'>***********************************************************</span>")
 
 /datum/buildmode_mode/say/handle_click(mob/user, params, atom/object)
-	if(istype(object, /mob))
+	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.")