Adds TTS to the game. Players can select their own voices in preferences. (#74775)

Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>
Co-authored-by: Kyle Spier-Swenson <kyleshome@gmail.com>
Co-authored-by: Iamgoofball <iamgoofball@gmail.com>
Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
This commit is contained in:
Watermelon914
2023-05-16 00:21:54 +01:00
committed by GitHub
parent cb38c9d429
commit a98706ff8b
39 changed files with 783 additions and 32 deletions
+2 -2
View File
@@ -19,7 +19,7 @@
else
return ..()
/mob/living/brain/treat_message(message, capitalize_message = TRUE)
/mob/living/brain/treat_message(message, tts_message, tts_filter, capitalize_message = TRUE)
if(capitalize_message)
message = capitalize(message)
return message
return list(message = message, tts_message = message, tts_filter = list())
@@ -3,6 +3,9 @@
dna?.species?.on_owner_login(src)
if(SStts.tts_enabled && !voice)
voice = pick(SStts.available_speakers)
if(!LAZYLEN(afk_thefts))
return
+41 -9
View File
@@ -179,7 +179,10 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
else
log_talk(message, LOG_SAY, forced_by = forced, custom_say_emote = message_mods[MODE_CUSTOM_SAY_EMOTE])
message = treat_message(message) // unfortunately we still need this
var/list/message_data = treat_message(message) // unfortunately we still need this
message = message_data["message"]
var/tts_message = message_data["tts_message"]
var/list/tts_filter = message_data["tts_filter"]
spans |= speech_span
@@ -200,10 +203,14 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
if(!HAS_TRAIT(src, TRAIT_SIGN_LANG)) // if using sign language skip sending the say signal
// Make sure the arglist is passed exactly - don't pass a copy of it. Say signal handlers will modify some of the parameters.
var/last_message = message
var/sigreturn = SEND_SIGNAL(src, COMSIG_MOB_SAY, args)
if(last_message != message)
tts_message = message
if(sigreturn & COMPONENT_UPPERCASE_SPEECH)
message = uppertext(message)
if(!message)
if(succumbed)
succumb()
@@ -238,8 +245,7 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
if(pressure < ONE_ATMOSPHERE*0.4) //Thin air, let's italicise the message
spans |= SPAN_ITALICS
send_speech(message, message_range, src, bubble_type, spans, language, message_mods)//roughly 58% of living/say()'s total cost
send_speech(message, message_range, src, bubble_type, spans, language, message_mods, tts_message = tts_message, tts_filter = tts_filter)//roughly 58% of living/say()'s total cost
if(succumbed)
succumb(TRUE)
to_chat(src, compose_message(src, language, message, , spans, message_mods))
@@ -321,7 +327,7 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
show_message(message, MSG_AUDIBLE, deaf_message, deaf_type, avoid_highlight)
return message
/mob/living/send_speech(message_raw, message_range = 6, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language = null, list/message_mods = list(), forced = null)
/mob/living/send_speech(message_raw, message_range = 6, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language = null, list/message_mods = list(), forced = null, tts_message, list/tts_filter)
var/whisper_range = 0
var/is_speaker_whispering = FALSE
if(message_mods[WHISPER_MODE]) //If we're whispering
@@ -360,10 +366,27 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
//speech bubble
var/list/speech_bubble_recipients = list()
var/found_client = FALSE
var/talk_icon_state = say_test(message_raw)
for(var/mob/M in listening)
if(M.client && (!M.client.prefs.read_preference(/datum/preference/toggle/enable_runechat) || (SSlag_switch.measures[DISABLE_RUNECHAT] && !HAS_TRAIT(src, TRAIT_BYPASS_MEASURES))))
speech_bubble_recipients.Add(M.client)
if(M.client)
if(!M.client.prefs.read_preference(/datum/preference/toggle/enable_runechat) || (SSlag_switch.measures[DISABLE_RUNECHAT] && !HAS_TRAIT(src, TRAIT_BYPASS_MEASURES)))
speech_bubble_recipients.Add(M.client)
found_client = TRUE
if(voice && found_client && !message_mods[MODE_CUSTOM_SAY_ERASE_INPUT] && !HAS_TRAIT(src, TRAIT_SIGN_LANG))
var/tts_message_to_use = tts_message
if(!tts_message_to_use)
tts_message_to_use = message_raw
var/list/filter = list()
if(length(voice_filter) > 0)
filter += voice_filter
if(length(tts_filter) > 0)
filter += tts_filter.Join(",")
INVOKE_ASYNC(SStts, TYPE_PROC_REF(/datum/controller/subsystem/tts, queue_tts_message), src, html_decode(tts_message_to_use), message_language, voice, filter.Join(","), message_range = message_range)
var/image/say_popup = image('icons/mob/effects/talk.dmi', src, "[bubble_type][talk_icon_state]", FLY_LAYER)
SET_PLANE_EXPLICIT(say_popup, ABOVE_GAME_PLANE, src)
@@ -416,16 +439,25 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
* message - The message to treat.
* capitalize_message - Whether we run capitalize() on the message after we're done.
*/
/mob/living/proc/treat_message(message, capitalize_message = TRUE)
/mob/living/proc/treat_message(message, tts_message, tts_filter, capitalize_message = TRUE)
if(HAS_TRAIT(src, TRAIT_UNINTELLIGIBLE_SPEECH))
message = unintelligize(message)
SEND_SIGNAL(src, COMSIG_LIVING_TREAT_MESSAGE, args)
tts_filter = list()
var/list/data = list(message, tts_message, tts_filter)
SEND_SIGNAL(src, COMSIG_LIVING_TREAT_MESSAGE, data)
message = data[TREAT_MESSAGE_ARG]
tts_message = data[TREAT_TTS_MESSAGE_ARG]
tts_filter = data[TREAT_TTS_FILTER_ARG]
if(!tts_message)
tts_message = message
if(capitalize_message)
message = capitalize(message)
tts_message = capitalize(tts_message)
return message
return list(message = message, tts_message = tts_message, tts_filter = tts_filter)
/mob/living/proc/radio(message, list/message_mods = list(), list/spans, language)
var/obj/item/implant/radio/imp = locate() in src
@@ -13,6 +13,7 @@
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
examine_cursor_icon = null
fire_stack_decay_rate = -0.55
voice_filter = "afftfilt=real='hypot(re,im)*sin(0)':imag='hypot(re,im)*cos(0)':win_size=512:overlap=1,rubberband=pitch=0.8"
var/datum/ai_laws/laws = null//Now... THEY ALL CAN ALL HAVE LAWS
var/last_lawchange_announce = 0
var/list/alarms_to_show = list()
@@ -51,8 +52,11 @@
var/obj/item/modular_computer/pda/silicon/modularInterface
/mob/living/silicon/Initialize(mapload)
. = ..()
if(SStts.tts_enabled)
voice = pick(SStts.available_speakers)
GLOB.silicon_mobs += src
faction += FACTION_SILICON
if(ispath(radio))
@@ -82,7 +82,7 @@
if(bonus_overlays)
. += bonus_overlays
/mob/living/simple_animal/robot_customer/send_speech(message, message_range, obj/source, bubble_type, list/spans, datum/language/message_language, list/message_mods, forced)
/mob/living/simple_animal/robot_customer/send_speech(message, message_range, obj/source, bubble_type, list/spans, datum/language/message_language, list/message_mods, forced, tts_message, list/tts_filter)
. = ..()
var/datum/customer_data/customer_info = ai_controller.blackboard[BB_CUSTOMER_CUSTOMERINFO]
playsound(src, customer_info.speech_sound, 30, extrarange = MEDIUM_RANGE_SOUND_EXTRARANGE, falloff_distance = 5)
@@ -898,13 +898,18 @@ GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list(
speak = list("Poly wanna cracker!", ":e Check the crystal, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN MODSUITS?",":e OH GOD ITS ABOUT TO DELAMINATE CALL THE SHUTTLE")
gold_core_spawnable = NO_SPAWN
speak_chance = 3
voice_filter = "rubberband=pitch=1.5"
var/memory_saved = FALSE
var/rounds_survived = 0
var/longest_survival = 0
var/longest_deathstreak = 0
/mob/living/simple_animal/parrot/poly/Initialize(mapload)
ears = new /obj/item/radio/headset/headset_eng(src)
if(SStts.tts_enabled)
voice = pick(SStts.available_speakers)
available_channels = list(":e")
Read_Memory()
if(rounds_survived == longest_survival)
+1
View File
@@ -29,6 +29,7 @@
/mob/Login()
if(!client)
return FALSE
canon_client = client
add_to_player_list()
lastKnownIP = client.address