mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-14 10:53:42 +00:00
hear_intercept is removed in favor of having the things that care register for the COMSIG_MOVABLE_HEAR signal instead. The signal has been changed to be like the speech one with an args list. Nanite datums no longer register for the hearing signal just in case, only the voice sensor nanite program does. Dead code has been removed from to_chat, the savefile/sound checks being just-in-case boilerplate checks made during the conversion to to_chat, the replacetexts sidestepping a byond bug that was fixed in 512.1420.
210 lines
6.7 KiB
Plaintext
210 lines
6.7 KiB
Plaintext
/*
|
|
Miauw's big Say() rewrite.
|
|
This file has the basic atom/movable level speech procs.
|
|
And the base of the send_speech() proc, which is the core of saycode.
|
|
*/
|
|
GLOBAL_LIST_INIT(freqtospan, list(
|
|
"[FREQ_SCIENCE]" = "sciradio",
|
|
"[FREQ_MEDICAL]" = "medradio",
|
|
"[FREQ_ENGINEERING]" = "engradio",
|
|
"[FREQ_SUPPLY]" = "suppradio",
|
|
"[FREQ_SERVICE]" = "servradio",
|
|
"[FREQ_SECURITY]" = "secradio",
|
|
"[FREQ_COMMAND]" = "comradio",
|
|
"[FREQ_AI_PRIVATE]" = "aiprivradio",
|
|
"[FREQ_SYNDICATE]" = "syndradio",
|
|
"[FREQ_CENTCOM]" = "centcomradio",
|
|
"[FREQ_CTF_RED]" = "redteamradio",
|
|
"[FREQ_CTF_BLUE]" = "blueteamradio"
|
|
))
|
|
|
|
/atom/movable/proc/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
|
if(!can_speak())
|
|
return
|
|
if(message == "" || !message)
|
|
return
|
|
spans |= speech_span
|
|
if(!language)
|
|
language = get_default_language()
|
|
send_speech(message, 7, src, , spans, message_language=language)
|
|
|
|
/atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
|
|
SEND_SIGNAL(src, COMSIG_MOVABLE_HEAR, args)
|
|
|
|
/atom/movable/proc/can_speak()
|
|
return 1
|
|
|
|
/atom/movable/proc/send_speech(message, range = 7, obj/source = src, bubble_type, list/spans, datum/language/message_language = null, message_mode)
|
|
var/rendered = compose_message(src, message_language, message, , spans, message_mode)
|
|
for(var/_AM in get_hearers_in_view(range, source))
|
|
var/atom/movable/AM = _AM
|
|
AM.Hear(rendered, src, message_language, message, , spans, message_mode)
|
|
|
|
/atom/movable/proc/compose_message(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, face_name = FALSE)
|
|
//This proc uses text() because it is faster than appending strings. Thanks BYOND.
|
|
//Basic span
|
|
var/spanpart1 = "<span class='[radio_freq ? get_radio_span(radio_freq) : "game say"]'>"
|
|
//Start name span.
|
|
var/spanpart2 = "<span class='name'>"
|
|
//Radio freq/name display
|
|
var/freqpart = radio_freq ? "\[[get_radio_name(radio_freq)]\] " : ""
|
|
//Speaker name
|
|
var/namepart = "[speaker.GetVoice()][speaker.get_alt_name()]"
|
|
if(face_name && ishuman(speaker))
|
|
var/mob/living/carbon/human/H = speaker
|
|
namepart = "[H.get_face_name()]" //So "fake" speaking like in hallucinations does not give the speaker away if disguised
|
|
//End name span.
|
|
var/endspanpart = "</span>"
|
|
|
|
//Message
|
|
var/messagepart = " <span class='message'>[lang_treat(speaker, message_language, raw_message, spans, message_mode)]</span></span>"
|
|
|
|
var/languageicon = ""
|
|
var/datum/language/D = GLOB.language_datum_instances[message_language]
|
|
if(istype(D) && D.display_icon(src))
|
|
languageicon = "[D.get_icon()] "
|
|
|
|
return "[spanpart1][spanpart2][freqpart][languageicon][compose_track_href(speaker, namepart)][namepart][compose_job(speaker, message_language, raw_message, radio_freq)][endspanpart][messagepart]"
|
|
|
|
/atom/movable/proc/compose_track_href(atom/movable/speaker, message_langs, raw_message, radio_freq)
|
|
return ""
|
|
|
|
/atom/movable/proc/compose_job(atom/movable/speaker, message_langs, raw_message, radio_freq)
|
|
return ""
|
|
|
|
/atom/movable/proc/say_mod(input, message_mode)
|
|
var/ending = copytext(input, length(input))
|
|
if(copytext(input, length(input) - 1) == "!!")
|
|
return verb_yell
|
|
else if(ending == "?")
|
|
return verb_ask
|
|
else if(ending == "!")
|
|
return verb_exclaim
|
|
else
|
|
return verb_say
|
|
|
|
/atom/movable/proc/say_quote(input, list/spans=list(speech_span), message_mode)
|
|
if(!input)
|
|
input = "..."
|
|
|
|
if(copytext(input, length(input) - 1) == "!!")
|
|
spans |= SPAN_YELL
|
|
|
|
var/spanned = attach_spans(input, spans)
|
|
return "[say_mod(input, message_mode)], \"[spanned]\""
|
|
|
|
/atom/movable/proc/lang_treat(atom/movable/speaker, datum/language/language, raw_message, list/spans, message_mode)
|
|
if(has_language(language))
|
|
var/atom/movable/AM = speaker.GetSource()
|
|
if(AM) //Basically means "if the speaker is virtual"
|
|
return AM.say_quote(raw_message, spans, message_mode)
|
|
else
|
|
return speaker.say_quote(raw_message, spans, message_mode)
|
|
else if(language)
|
|
var/atom/movable/AM = speaker.GetSource()
|
|
var/datum/language/D = GLOB.language_datum_instances[language]
|
|
raw_message = D.scramble(raw_message)
|
|
if(AM)
|
|
return AM.say_quote(raw_message, spans, message_mode)
|
|
else
|
|
return speaker.say_quote(raw_message, spans, message_mode)
|
|
else
|
|
return "makes a strange sound."
|
|
|
|
/proc/get_radio_span(freq)
|
|
var/returntext = GLOB.freqtospan["[freq]"]
|
|
if(returntext)
|
|
return returntext
|
|
return "radio"
|
|
|
|
/proc/get_radio_name(freq)
|
|
var/returntext = GLOB.reverseradiochannels["[freq]"]
|
|
if(returntext)
|
|
return returntext
|
|
return "[copytext("[freq]", 1, 4)].[copytext("[freq]", 4, 5)]"
|
|
|
|
/proc/attach_spans(input, list/spans)
|
|
return "[message_spans_start(spans)][input]</span>"
|
|
|
|
/proc/message_spans_start(list/spans)
|
|
var/output = "<span class='"
|
|
for(var/S in spans)
|
|
output = "[output][S] "
|
|
output = "[output]'>"
|
|
return output
|
|
|
|
/proc/say_test(text)
|
|
var/ending = copytext(text, length(text))
|
|
if (ending == "?")
|
|
return "1"
|
|
else if (ending == "!")
|
|
return "2"
|
|
return "0"
|
|
|
|
/atom/movable/proc/GetVoice()
|
|
return "[src]" //Returns the atom's name, prepended with 'The' if it's not a proper noun
|
|
|
|
/atom/movable/proc/IsVocal()
|
|
return 1
|
|
|
|
/atom/movable/proc/get_alt_name()
|
|
|
|
//HACKY VIRTUALSPEAKER STUFF BEYOND THIS POINT
|
|
//these exist mostly to deal with the AIs hrefs and job stuff.
|
|
|
|
/atom/movable/proc/GetJob() //Get a job, you lazy butte
|
|
|
|
/atom/movable/proc/GetSource()
|
|
|
|
/atom/movable/proc/GetRadio()
|
|
|
|
//VIRTUALSPEAKERS
|
|
/atom/movable/virtualspeaker
|
|
var/job
|
|
var/atom/movable/source
|
|
var/obj/item/radio/radio
|
|
|
|
INITIALIZE_IMMEDIATE(/atom/movable/virtualspeaker)
|
|
/atom/movable/virtualspeaker/Initialize(mapload, atom/movable/M, radio)
|
|
. = ..()
|
|
radio = radio
|
|
source = M
|
|
if (istype(M))
|
|
name = M.GetVoice()
|
|
verb_say = M.verb_say
|
|
verb_ask = M.verb_ask
|
|
verb_exclaim = M.verb_exclaim
|
|
verb_yell = M.verb_yell
|
|
|
|
// The mob's job identity
|
|
if(ishuman(M))
|
|
// Humans use their job as seen on the crew manifest. This is so the AI
|
|
// can know their job even if they don't carry an ID.
|
|
var/datum/data/record/findjob = find_record("name", name, GLOB.data_core.general)
|
|
if(findjob)
|
|
job = findjob.fields["rank"]
|
|
else
|
|
job = "Unknown"
|
|
else if(iscarbon(M)) // Carbon nonhuman
|
|
job = "No ID"
|
|
else if(isAI(M)) // AI
|
|
job = "AI"
|
|
else if(iscyborg(M)) // Cyborg
|
|
var/mob/living/silicon/robot/B = M
|
|
job = "[B.designation] Cyborg"
|
|
else if(istype(M, /mob/living/silicon/pai)) // Personal AI (pAI)
|
|
job = "Personal AI"
|
|
else if(isobj(M)) // Cold, emotionless machines
|
|
job = "Machine"
|
|
else // Unidentifiable mob
|
|
job = "Unknown"
|
|
|
|
/atom/movable/virtualspeaker/GetJob()
|
|
return job
|
|
|
|
/atom/movable/virtualspeaker/GetSource()
|
|
return source
|
|
|
|
/atom/movable/virtualspeaker/GetRadio()
|
|
return radio
|