diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm
index 506080fdc9..c87338d26c 100644
--- a/code/modules/mob/living/carbon/human/say.dm
+++ b/code/modules/mob/living/carbon/human/say.dm
@@ -1,10 +1,10 @@
-/mob/living/carbon/human/say(var/message)
+/mob/living/carbon/human/say(var/message,var/whispering=0)
var/alt_name = ""
if(name != GetVoice())
alt_name = "(as [get_id_name("Unknown")])"
message = sanitize(message)
- ..(message, alt_name = alt_name)
+ ..(message, alt_name = alt_name, whispering = whispering)
/mob/living/carbon/human/proc/forcesay(list/append)
if(stat == CONSCIOUS)
@@ -181,9 +181,6 @@
if(has_radio)
R.talk_into(src,message,null,verb,speaking)
used_radios += R
- if("whisper")
- whisper_say(message, speaking, alt_name)
- return 1
else
if(message_mode)
if(l_ear && istype(l_ear,/obj/item/device/radio))
diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm
deleted file mode 100644
index 534f660a44..0000000000
--- a/code/modules/mob/living/carbon/human/whisper.dm
+++ /dev/null
@@ -1,132 +0,0 @@
-//Lallander was here
-/mob/living/carbon/human/whisper(message as text)
- var/alt_name = ""
-
- if(say_disabled) //This is here to try to identify lag problems
- usr << "\red Speech is currently admin-disabled."
- return
-
- message = sanitize(message)
- log_whisper("[src.name]/[src.key] : [message]")
-
- if (src.client)
- if (src.client.prefs.muted & MUTE_IC)
- src << "\red You cannot whisper (muted)."
- return
-
- if (src.client.handle_spam_prevention(message,MUTE_IC))
- return
-
- if (src.stat == 2)
- return src.say_dead(message)
-
- if (src.stat)
- return
-
- if(name != GetVoice())
- alt_name = "(as [get_id_name("Unknown")])"
-
- //parse the language code and consume it
- var/datum/language/speaking = parse_language(message)
- if (speaking)
- message = copytext(message,2+length(speaking.key))
-
- whisper_say(message, speaking, alt_name)
-
-
-//This is used by both the whisper verb and human/say() to handle whispering
-/mob/living/carbon/human/proc/whisper_say(var/message, var/datum/language/speaking = null, var/alt_name="", var/verb="whispers")
-
- if (is_muzzled())
- src << "You're muzzled and cannot speak!"
- return
-
- var/message_range = 1
- var/eavesdropping_range = 2
- var/watching_range = 5
- var/italics = 1
-
- var/not_heard //the message displayed to people who could not hear the whispering
- var/adverb
- if (speaking)
- if (speaking.whisper_verb)
- verb = speaking.whisper_verb
- not_heard = "[verb] something"
- else
- adverb = pick("quietly", "softly")
- verb = speaking.speech_verb
- not_heard = "[speaking.speech_verb] something [adverb]"
- else
- not_heard = "[verb] something" //TODO get rid of the null language and just prevent speech if language is null
-
- message = capitalize(trim(message))
-
- //speech problems
- if(!(speaking && (speaking.flags & NO_STUTTER)))
- var/list/message_data = list(message, verb, 1)
- if(handle_speech_problems(message_data))
- message = message_data[1]
-
- if(!message_data[3]) //if a speech problem like hulk forces someone to yell then everyone hears it
- verb = message_data[2] //assume that if they are going to force not-whispering then they will set an appropriate verb too
- message_range = world.view
- else if(verb != message_data[2])
- adverb = pick("quietly", "softly") //new verb given, so 'whisperize' it with an adverb
- verb = message_data[2]
-
- //consoldiate the adverb if we have one
- if(adverb) verb = "[verb] [adverb]"
-
- if(!message || message=="")
- return
-
- var/list/listening = hearers(message_range, src)
- listening |= src
-
- //ghosts
- for (var/mob/M in dead_mob_list) //does this include players who joined as observers as well?
- if (!(M.client))
- continue
- if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
- listening |= M
-
- //Pass whispers on to anything inside the immediate listeners.
- for(var/mob/L in listening)
- for(var/mob/C in L.contents)
- if(istype(C,/mob/living))
- listening += C
-
- //pass on the message to objects that can hear us.
- for (var/obj/O in view(message_range, src))
- spawn (0)
- if (O)
- O.hear_talk(src, message, verb, speaking)
-
- var/list/eavesdropping = hearers(eavesdropping_range, src)
- eavesdropping -= src
- eavesdropping -= listening
-
- var/list/watching = hearers(watching_range, src)
- watching -= src
- watching -= listening
- watching -= eavesdropping
-
- //now mobs
- var/speech_bubble_test = say_test(message)
- var/image/speech_bubble = image('icons/mob/talk.dmi',src,"h[speech_bubble_test]")
- spawn(30) qdel(speech_bubble)
-
- for(var/mob/M in listening)
- M << speech_bubble
- M.hear_say(message, verb, speaking, alt_name, italics, src)
-
- if (eavesdropping.len)
- var/new_message = stars(message) //hopefully passing the message twice through stars() won't hurt... I guess if you already don't understand the language, when they speak it too quietly to hear normally you would be able to catch even less.
- for(var/mob/M in eavesdropping)
- M << speech_bubble
- M.hear_say(new_message, verb, speaking, alt_name, italics, src)
-
- if (watching.len)
- var/rendered = "[src.name] [not_heard]."
- for (var/mob/M in watching)
- M.show_message(rendered, 2)
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index df769d1c88..73427a63ed 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -82,21 +82,18 @@ proc/get_radio_key_from_channel(var/channel)
/mob/living/proc/get_default_language()
return default_language
-/mob/living/proc/is_muzzled()
- return 0
-
//Takes a list of the form list(message, verb, whispering) and modifies it as needed
//Returns 1 if a speech problem was applied, 0 otherwise
/mob/living/proc/handle_speech_problems(var/list/message_data)
var/message = message_data[1]
var/verb = message_data[2]
-
+ var/whispering = message_data[3]
. = 0
if((HULK in mutations) && health >= 25 && length(message))
message = "[uppertext(message)]!!!"
verb = pick("yells","roars","hollers")
- message_data[3] = 0
+ whispering = 0
. = 1
if(slurring)
message = slur(message)
@@ -109,6 +106,7 @@ proc/get_radio_key_from_channel(var/channel)
message_data[1] = message
message_data[2] = verb
+ message_data[2] = whispering
/mob/living/proc/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
if(message_mode == "intercom")
@@ -130,33 +128,42 @@ proc/get_radio_key_from_channel(var/channel)
return "asks"
return verb
-/mob/living/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="")
+/mob/living/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/whispering = 0)
+ //If you're muted for IC chat
if(client)
- if(client.prefs.muted & MUTE_IC)
- src << "\red You cannot speak in IC (Muted)."
+ if((client.prefs.muted & MUTE_IC) || say_disabled)
+ src << "You cannot speak in IC (Muted)."
return
+ //Redirect to say_dead if talker is dead
if(stat)
- if(stat == 2)
+ if(stat == DEAD)
return say_dead(message)
return
+ //Parse the mode
var/message_mode = parse_message_mode(message, "headset")
+ //Maybe they are using say/whisper to do a quick emote, so do those
switch(copytext(message,1,2))
if("*") return emote(copytext(message,2))
if("^") return custom_emote(1, copytext(message,2))
- //parse the radio code and consume it
+ //Parse the radio code and consume it
if (message_mode)
if (message_mode == "headset")
message = copytext(message,2) //it would be really nice if the parse procs could do this for us.
+ else if (message_mode == "whisper")
+ whispering = 1
+ message_mode = null
+ message = copytext(message,3)
else
message = copytext(message,3)
+ //Clean up any remaining space on the left
message = trim_left(message)
- //parse the language code and consume it
+ //Parse the language code and consume it
if(!speaking)
speaking = parse_language(message)
if(speaking)
@@ -164,43 +171,72 @@ proc/get_radio_key_from_channel(var/channel)
else
speaking = get_default_language()
- // This is broadcast to all mobs with the language,
- // irrespective of distance or anything else.
+ //HIVEMIND languages always send to all people with that language
if(speaking && (speaking.flags & HIVEMIND))
speaking.broadcast(src,trim(message))
return 1
- verb = say_quote(message, speaking)
-
+ //Self explanatory.
if(is_muzzled())
src << "You're muzzled and cannot speak!"
return
+ //Clean up any remaining junk on the left like spaces.
message = trim_left(message)
+ //Autohiss handles auto-rolling tajaran R's and unathi S's/Z's
message = handle_autohiss(message, speaking)
+ //Whisper vars
+ var/w_scramble_range = 5 //The range at which you get ***as*th**wi****
+ var/w_adverb //An adverb prepended to the verb in whispers
+ var/w_not_heard //The message for people in watching range
+
+ //Handle language-specific verbs and adverb setup if necessary
+ if(!whispering) //Just doing normal 'say' (for now, may change below)
+ verb = say_quote(message, speaking)
+ else if(whispering && speaking.whisper_verb) //Language has defined whisper verb
+ verb = speaking.whisper_verb
+ w_not_heard = "[verb] something"
+ else //Whispering but language has no whisper verb, use say verb
+ w_adverb = pick("quietly", "softly")
+ verb = speaking.speech_verb
+ w_not_heard = "[speaking.speech_verb] something [w_adverb]"
+
+ //For speech disorders (hulk, slurring, stuttering)
if(!(speaking && (speaking.flags & NO_STUTTER)))
- var/list/message_data = list(message, verb, 0)
+ var/list/message_data = list(message, verb, whispering)
if(handle_speech_problems(message_data))
message = message_data[1]
- verb = message_data[2]
+ whispering = message_data[3]
+ if(verb != message_data[2]) //They changed our verb
+ if(whispering)
+ w_adverb = pick("quietly", "softly")
+ verb = message_data[2]
+
+ //Whisper may have adverbs, add those if one was set
+ if(w_adverb) verb = "[verb] [w_adverb]"
+
+ //If something nulled or emptied the message, forget it
if(!message || message == "")
return 0
+ //Radio message handling
var/list/obj/item/used_radios = new
- if(handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name))
+ if(handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, whispering))
return 1
+ //For languages with actual speech sounds
var/list/handle_v = handle_speech_sound()
var/sound/speech_sound = handle_v[1]
var/sound_vol = handle_v[2]
- var/italics = 0
+ //Default range and italics, may be overridden past here
var/message_range = world.view
+ var/italics = 0
- //speaking into radios
+ //Speaking into radios
if(used_radios.len)
italics = 1
message_range = 1
@@ -215,9 +251,13 @@ proc/get_radio_key_from_channel(var/channel)
if (speech_sound)
sound_vol *= 0.5
- var/turf/T = get_turf(src)
+ //Set vars if we're still whispering by this point
+ if(whispering)
+ italics = 1
+ message_range = 1
+ sound_vol *= 0.5
- //handle nonverbal and sign languages here
+ //Handle nonverbal and sign languages here
if (speaking)
if (speaking.flags & NONVERBAL)
if (prob(30))
@@ -226,42 +266,64 @@ proc/get_radio_key_from_channel(var/channel)
if (speaking.flags & SIGNLANG)
return say_signlang(message, pick(speaking.signlang_verb), speaking)
+ //These will contain the main receivers of the message
var/list/listening = list()
var/list/listening_obj = list()
+ //Atmosphere calculations (speaker's side only, for now)
+ var/turf/T = get_turf(src)
if(T)
- //make sure the air can transmit speech - speaker's side
+ //Air is too thin to carry sound at all, contact speech only
var/datum/gas_mixture/environment = T.return_air()
var/pressure = (environment)? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE)
message_range = 1
- if (pressure < ONE_ATMOSPHERE*0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
+ //Air is nearing minimum levels, make text italics as a hint, and muffle sound
+ if (pressure < ONE_ATMOSPHERE*0.4)
italics = 1
- sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
+ sound_vol *= 0.5
- var/list/results = get_mobs_and_objs_in_view_fast(T, message_range)
+ //Obtain the mobs and objects in the message range
+ var/list/results = get_mobs_and_objs_in_view_fast(T, world.view)
listening = results["mobs"]
listening_obj = results["objs"]
+ else
+ return 1 //If we're in nullspace, then forget it.
+ //The 'post-say' static speech bubble
var/speech_bubble_test = say_test(message)
var/image/speech_bubble = image('icons/mob/talk.dmi',src,"h[speech_bubble_test]")
spawn(30) qdel(speech_bubble)
+ //Main 'say' and 'whisper' message delivery
for(var/mob/M in listening)
- try
- M << speech_bubble
- M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol)
- catch(var/exception/e)
- log_debug("hear_say exception on mob - [e] in [e.file]:[e.line]")
+ spawn(0) //Using spawns to queue all the messages for AFTER this proc is done, and stop runtimes
+ if(M && src) //If we still exist, when the spawn processes
+ var/dst = get_dist(get_turf(M),get_turf(src))
+
+ if(dst <= message_range) //Inside normal message range, FYI -1 is "from self to self" range
+ M << speech_bubble
+ M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol)
+
+ if(whispering) //Don't even bother with these unless whispering
+ if(dst > message_range && dst <= w_scramble_range) //Inside whisper scramble range
+ M << speech_bubble
+ M.hear_say(stars(message), verb, speaking, alt_name, italics, src, speech_sound, sound_vol*0.2)
+ if(dst > w_scramble_range && dst <= world.view) //Inside whisper 'visible' range
+ M.show_message("[src.name] [w_not_heard].", 2)
+
+ //Object message delivery
for(var/obj/O in listening_obj)
- try
- O.hear_talk(src, message, verb, speaking)
- catch(var/exception/e)
- log_debug("hear_talk exception on obj - [e] in [e.file]:[e.line]")
+ spawn(0)
+ if(O && src) //If we still exist, when the spawn processes
+ var/dst = get_dist(get_turf(O),get_turf(src))
+ if(dst <= message_range)
+ O.hear_talk(src, message, verb, speaking)
- log_say("[name]/[key] : [message]")
+ //Log the message to file
+ log_say("[name]/[key][whispering ? " (W)" : ""]: [message]")
return 1
/mob/living/proc/say_signlang(var/message, var/verb="gestures", var/datum/language/language)
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index ec47effaba..f7aaa52f78 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -1,29 +1,15 @@
/mob/proc/say()
return
-/mob/verb/whisper()
+/mob/verb/whisper(message as text)
set name = "Whisper"
set category = "IC"
- return
+
+ usr.say(message,whispering=1)
/mob/verb/say_verb(message as text)
set name = "Say"
set category = "IC"
- if(say_disabled) //This is here to try to identify lag problems
- usr << "\red Speech is currently admin-disabled."
- return
- //Let's try to make users fix their errors - we try to detect single, out-of-place letters and 'unintended' words
- /*
- var/first_letter = copytext(message,1,2)
- if((copytext(message,2,3) == " " && first_letter != "I" && first_letter != "A" && first_letter != ";") || cmptext(copytext(message,1,5), "say ") || cmptext(copytext(message,1,4), "me ") || cmptext(copytext(message,1,6), "looc ") || cmptext(copytext(message,1,5), "ooc ") || cmptext(copytext(message,2,6), "say "))
- var/response = alert(usr, "Do you really want to say this using the *say* verb?\n\n[message]\n", "Confirm your message", "Yes", "Edit message", "No")
- if(response == "Edit message")
- message = input(usr, "Please edit your message carefully:", "Edit message", message)
- if(!message)
- return
- else if(response == "No")
- return
- */
set_typing_indicator(0)
usr.say(message)
@@ -62,7 +48,7 @@
/mob/proc/say_understands(var/mob/other,var/datum/language/speaking = null)
- if (src.stat == 2) //Dead
+ if (src.stat == DEAD)
return 1
//Universal speak makes everything understandable, for obvious reasons.
diff --git a/polaris.dme b/polaris.dme
index 1ab16549c5..b352561b1e 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -1380,7 +1380,6 @@
#include "code\modules\mob\living\carbon\human\stripping.dm"
#include "code\modules\mob\living\carbon\human\unarmed_attack.dm"
#include "code\modules\mob\living\carbon\human\update_icons.dm"
-#include "code\modules\mob\living\carbon\human\whisper.dm"
#include "code\modules\mob\living\carbon\human\species\species.dm"
#include "code\modules\mob\living\carbon\human\species\species_attack.dm"
#include "code\modules\mob\living\carbon\human\species\species_getters.dm"