Files
Aurora.3/code/modules/mob/hear_say.dm
T
WildkinsandGitHub e1770df81e Lag War Day 4: Under Pressure, High Voltage (#21878)
Replace /datum/gas_mixture/proc/return_pressure with XGM_PRESSURE(xgm)
macro. Having such a relatively simple statement contributing proc
overhead to procs called millions of times is ridiculous

Rename /datum/gas_mixture/proc/zburn to react, deleting the old react
which was just an alias for it. Free proc overhead

Turn check_combustibility into a macro CHECK_COMBUSTIBLE(is_cmb, xgm).
also rewrite it slightly so that it only needs to do one pass. Its a bit
nasty so I apologize for that, but speeeeed.

Delete most powernet and obj/machinery/power procs for handling power,
replacing them with macros. The fact that we were unironically calling a
draw_power() on APCs to call draw_power() on their terminals to call
draw_power() on their powernet every single process tick was insane.

Turn `between` into a macro alias for clamp() since the param order is
different

turn `Percent` into a macro AS_PCT

Rewrite significant chunks of update_canmove so its not quite as
horrifying of a proc and hopefully doesn't eat the entire mob subsystem
every movement now
2026-02-27 00:35:41 +00:00

314 lines
12 KiB
Plaintext

// At minimum every mob has a hear_say proc.
/**
* hear_say's return value determines whether or not the mob in question also receives a langchat image.
*/
/mob/proc/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol, var/font_size = null)
if(!istype(src, /mob/living/test) && cant_hear())
return FALSE
if(speaker && !istype(speaker, /mob/living/test) && (!speaker.client && istype(src,/mob/abstract/ghost/observer) && client.prefs.toggles & CHAT_GHOSTEARS && !(speaker in view(src))))
//Does the speaker have a client? It's either random stuff that observers won't care about (Experiment 97B says, 'EHEHEHEHEHEHEHE')
//Or someone snoring. So we make it where they won't hear it.
return FALSE
//make sure the air can transmit speech - hearer's side
var/turf/T = get_turf(src)
var/vacuum_proof = ((language && (language.flags & PRESSUREPROOF)) || isghost(src))
var/speaker_name = speaker.name
if(ishuman(speaker))
var/mob/living/carbon/human/H = speaker
speaker_name = H.GetVoice()
if(T && !vacuum_proof) //Ghosts can hear even in vacuum.
var/datum/gas_mixture/environment = T.return_air()
var/pressure = SAFE_XGM_PRESSURE(environment)
var/distance_to_speaker = get_dist(speaker, src)
if(pressure < SOUND_MINIMUM_PRESSURE && distance_to_speaker > 1)
// Yeah, this isn't quite realistic to be able to see if someone is talking through, say, an opaque mask, but for gameplay purposes it should help indicate that you're not bugged.
if(distance_to_speaker <= 4 && !italics)
to_chat(src, SPAN_NOTICE("[speaker_name] talks, but you're in a vacuum. Maybe if you were close enough for the sound to transmit through touch..."))
return FALSE
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
italics = 1
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
if((language && (language.flags & KNOWONLYHEAR)) && !say_understands(speaker, language))
return TRUE
if(!vr_mob && (sleeping || stat == UNCONSCIOUS))
hear_sleep(message)
return FALSE
//non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet.
if (language && (language.flags & NONVERBAL))
if((!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src))) && !isghost(src))
message = stars(message)
if(!(language && (language.flags & INNATE)) && !say_understands(speaker, language)) // skip understanding checks for INNATE languages
message = language ? language.scramble(message, languages) : stars(message)
var/accent_icon = speaker.get_accent_icon(language, src)
if(italics)
message = "<i>[message]</i>"
var/track = null
if(isghost(src))
if(speaker_name != speaker.real_name && speaker.real_name)
speaker_name = "[speaker.real_name] ([speaker_name])"
track = "[ghost_follow_link(speaker, src)] "
if((client.prefs.toggles & CHAT_GHOSTEARS) && (get_turf(speaker) in view(src)))
message = "<b>[message]</b>"
if(isdeaf(src))
if(!language || !(language.flags & INNATE)) // INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set
if(speaker == src)
to_chat(src, SPAN_WARNING("You cannot hear yourself speak!"))
return FALSE
else
to_chat(src, "<span class='name'>[speaker_name]</span>[alt_name] talks but you cannot hear them.")
return FALSE
else
if(language)
if(font_size)
on_hear_say("[track][accent_icon ? accent_icon + " " : ""]<font size='[font_size]'><span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [language.format_message(message, verb)]</span></font>")
else
on_hear_say("[track][accent_icon ? accent_icon + " " : ""]<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [language.format_message(message, verb)]</span>")
else
if(font_size)
on_hear_say("[track][accent_icon ? accent_icon + " " : ""]<font size='[font_size]'><span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [verb], <span class='message'><span class='body'>\"[message]\"</span></span></span></font>")
else
on_hear_say("[track][accent_icon ? accent_icon + " " : ""]<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [verb], <span class='message'><span class='body'>\"[message]\"</span></span></span>")
if (speech_sound && (get_dist(speaker, src) <= world.view && src.z == speaker.z))
var/turf/source = speaker? get_turf(speaker) : get_turf(src)
playsound(source, speech_sound, sound_vol, vary = TRUE)
return TRUE
/mob/proc/cant_hear()
if(!client && !vr_mob)
return TRUE
return FALSE
/mob/living/carbon/cant_hear()
. = ..()
if(.)
var/datum/dionastats/DS = get_dionastats()
if(DS?.nym)
return FALSE
/mob/living/carbon/alien/diona/cant_hear()
. = ..()
if(. && detached && gestalt)
return FALSE
/mob/proc/on_hear_say(var/message)
to_chat(src, message)
if(vr_mob)
to_chat(vr_mob, message)
/mob/living/carbon/on_hear_say(var/message)
..()
var/datum/dionastats/DS = get_dionastats()
if(DS?.nym)
var/mob/living/carbon/alien/diona/D = DS.nym.resolve()
if(D)
to_chat(D, message)
/mob/living/carbon/alien/diona/on_hear_say(var/message)
to_chat(src, message)
if(detached && gestalt)
to_chat(gestalt, message)
/mob/living/silicon/on_hear_say(var/message)
var/time = say_timestamp()
to_chat(src, "[time] [message]")
if(vr_mob)
to_chat(vr_mob, "[time] [message]")
/mob/proc/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0)
if(!client && !vr_mob)
return
if(!vr_mob && (sleeping || stat == UNCONSCIOUS))
hear_sleep(message)
return
var/track = null
//non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet.
if (language && (language.flags & NONVERBAL))
if (!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src)))
message = stars(message)
if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages
if(!say_understands(speaker,language))
if(istype(speaker,/mob/living/simple_animal))
var/mob/living/simple_animal/S = speaker
if(S.speak && S.speak.len)
message = pick(S.speak)
else
return
else
if(language)
message = language.scramble(message, languages)
else
message = stars(message)
if(hard_to_hear)
message = stars(message)
var/speaker_name
if(speaker != null)
speaker_name = speaker.name
else
speaker_name = "Unknown"
if(ishuman(speaker))
speaker_name = speaker.GetVoice()
if(hard_to_hear)
speaker_name = "Unknown"
var/changed_voice
var/accent_icon = speaker.get_accent_icon(language, src)
accent_icon = accent_icon ? accent_icon + " " : ""
part_a = replacetext(part_a, "%ACCENT%", accent_icon)
if(istype(src, /mob/living/silicon/ai) && !hard_to_hear)
var/jobname // the mob's "job"
var/mob/living/carbon/human/impersonating //The crew member being impersonated, if any.
if (ishuman(speaker))
var/mob/living/carbon/human/H = speaker
if(H.wear_mask && istype(H.wear_mask,/obj/item/clothing/mask/gas/voice))
changed_voice = 1
var/list/impersonated = list()
var/mob/living/carbon/human/I = impersonated[speaker_name]
if(!I)
for(var/mob/living/carbon/human/M in GLOB.mob_list)
if(M.real_name == speaker_name)
I = M
impersonated[speaker_name] = I
break
// If I's display name is currently different from the voice name and using an agent ID then don't impersonate
// as this would allow the AI to track I and realize the mismatch.
if(I && !(I.name != speaker_name && I.wear_id && istype(I.wear_id,/obj/item/card/id/syndicate)))
impersonating = I
jobname = impersonating.get_assignment()
else
jobname = "Unknown"
else
jobname = H.get_assignment()
else if (iscarbon(speaker)) // Nonhuman carbon mob
jobname = "No id"
else if (isAI(speaker))
jobname = "AI"
else if (isrobot(speaker))
jobname = "Cyborg"
else if (istype(speaker, /mob/living/silicon/pai))
jobname = "Personal AI"
else
jobname = "Unknown"
if(changed_voice)
if(impersonating)
track = "<a class='ai_tracking' href='byond://?src=[REF(src)];trackname=[html_encode(speaker_name)];track=[REF(impersonating)]'>[speaker_name] ([jobname])</a>"
else
track = "[speaker_name] ([jobname])"
else
track = "<a class='ai_tracking' href='byond://?src=[REF(src)];trackname=[html_encode(speaker_name)];track=[REF(speaker)]'>[speaker_name] ([jobname])</a>"
if(isghost(src))
if(speaker != null)
if(speaker_name != speaker.real_name && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs.
speaker_name = "[speaker.real_name] ([speaker_name])"
track = "[ghost_follow_link(speaker, src)] "
var/formatted
if(language)
formatted = language.format_message_radio(message, verb)
else
formatted = "[verb], <span class=\"body\">\"[message]\"</span>"
formatted += part_c
if(isdeaf(src))
if(prob(20))
to_chat(src, SPAN_WARNING("You feel your headset vibrate but can hear nothing from it!"))
else
on_hear_radio(part_a, speaker_name, track, part_b, formatted, accent_icon)
/proc/say_timestamp()
return "<span class='say_quote'>\[[worldtime2text()]\]</span>"
/mob/proc/on_hear_radio(part_a, speaker_name, track, part_b, formatted, accent_icon)
to_chat(src, "[part_a][speaker_name][part_b][formatted]")
if(vr_mob)
to_chat(vr_mob, "[part_a][speaker_name][part_b][formatted]")
/mob/abstract/ghost/observer/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
to_chat(src, "[track][part_a][speaker_name][part_b][formatted]")
/mob/living/silicon/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
var/time = say_timestamp()
to_chat(src, "[time][part_a][speaker_name][part_b][formatted]")
if(vr_mob)
to_chat(vr_mob, "[time][part_a][speaker_name][part_b][formatted]")
/mob/living/silicon/ai/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
var/time = say_timestamp()
to_chat(src, "[time][part_a][track][part_b][formatted]")
if(vr_mob)
to_chat(vr_mob, "[time][part_a][track][part_b][formatted]")
/mob/proc/hear_signlang(var/message, var/verb = "gestures", var/datum/language/language, var/mob/speaker = null, var/list/sign_adv_length = null)
if(!client || !speaker)
return
if(say_understands(speaker, language))
message = "<B>[speaker]</B> [verb], \"[message]\""
else
if (length(sign_adv_length) <= 4)
sign_adv_length = list(" briefly", " a short message", " a message", " a lengthy message", " a very lengthy message")
var/adverb
var/length = length(message) * pick(0.8, 0.9, 1.0, 1.1, 1.2) //Inserts a little fuzziness.
switch(length)
if(0 to 12) adverb = sign_adv_length[1]
if(12 to 30) adverb = sign_adv_length[2]
if(30 to 48) adverb = sign_adv_length[3]
if(48 to 90) adverb = sign_adv_length[4]
else adverb = sign_adv_length[5]
message = "<B>[speaker]</B> [verb][adverb]."
if(src.status_flags & PASSEMOTES)
for(var/obj/item/holder/H in src.contents)
H.show_message(message)
for(var/mob/living/M in src.contents)
M.show_message(message)
src.show_message(message)
/mob/proc/hear_sleep(var/message)
if (isdeaf(src))
return
var/heard = ""
if(prob(15))
var/list/punctuation = list(",", "!", ".", ";", "?")
var/list/messages = text2list(message, " ")
var/R = rand(1, messages.len)
var/heardword = messages[R]
if(copytext(heardword,1, 1) in punctuation)
heardword = copytext(heardword,2)
if(copytext(heardword,-1) in punctuation)
heardword = copytext(heardword,1,length(heardword))
heard = "<span class = 'game_say'>...You hear something about...[heardword]</span>"
else
heard = "<span class = 'game_say'>...<i>You almost hear someone talking</i>...</span>"
to_chat(src, heard)