diff --git a/.gitignore b/.gitignore
index acd33544c90dc16..4e8ee8a37f91857 100644
--- a/.gitignore
+++ b/.gitignore
@@ -250,3 +250,7 @@ define_sanity_output.txt
# Running OpenDream locally
tgstation.json
+
+# Ignore cached sound files.
+/sound/tts_cache/**/*
+/sound/tts_scrambled/**/*
diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm
index fe002fef14f63dd..347dc58ead3de04 100644
--- a/code/__DEFINES/sound.dm
+++ b/code/__DEFINES/sound.dm
@@ -12,7 +12,7 @@
#define CHANNEL_ELEVATOR 1014
//THIS SHOULD ALWAYS BE THE LOWEST ONE!
//KEEP IT UPDATED
-#define CHANNEL_HIGHEST_AVAILABLE 1013
+#define CHANNEL_HIGHEST_AVAILABLE 1012 //ORIGINAL: 1013
#define MAX_INSTRUMENT_CHANNELS (128 * 6)
diff --git a/config/config.txt b/config/config.txt
index eba043797fff611..44c3cc4dae61520 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -6,6 +6,7 @@ $include comms.txt
$include logging.txt
$include resources.txt
$include nova/config_nova.txt
+$include ss220/ss220_config.txt
$include interviews.txt
$include lua.txt
$include auxtools.txt
diff --git a/config/ss220/ss220_config.txt b/config/ss220/ss220_config.txt
new file mode 100644
index 000000000000000..d7284e7bca3926f
--- /dev/null
+++ b/config/ss220/ss220_config.txt
@@ -0,0 +1,4 @@
+## Text-to-speech
+#TTS_TOKEN_SILERO mytoken
+#TTS_ENABLED
+#TTS_CACHE
diff --git a/modular_ss220/modules/tts/code/_tts_defines.dm b/modular_ss220/modules/tts/code/_tts_defines.dm
new file mode 100644
index 000000000000000..674d44c92968243
--- /dev/null
+++ b/modular_ss220/modules/tts/code/_tts_defines.dm
@@ -0,0 +1,78 @@
+#define SOUND_EFFECT_NONE 0
+#define SOUND_EFFECT_RADIO 1
+#define SOUND_EFFECT_ROBOT 2
+#define SOUND_EFFECT_RADIO_ROBOT 3
+#define SOUND_EFFECT_MEGAPHONE 4
+#define SOUND_EFFECT_MEGAPHONE_ROBOT 5
+
+#define CHANNEL_TTS_RADIO 1013
+
+#define TTS_TRAIT_PITCH_WHISPER (1<<1)
+#define TTS_TRAIT_RATE_FASTER (1<<2)
+#define TTS_TRAIT_RATE_MEDIUM (1<<3)
+
+#define rustg_file_write_b64decode(text, fname) RUSTG_CALL(RUST_G, "file_write")(text, fname, "true")
+
+// Hashing Operations //
+#define rustg_hash_string(algorithm, text) RUSTG_CALL(RUST_G, "hash_string")(algorithm, text)
+#define rustg_hash_file(algorithm, fname) RUSTG_CALL(RUST_G, "hash_file")(algorithm, fname)
+
+#define RUSTG_HASH_MD5 "md5"
+
+#ifdef RUSTG_OVERRIDE_BUILTINS
+ #define md5(thing) (isfile(thing) ? rustg_hash_file(RUSTG_HASH_MD5, "[thing]") : rustg_hash_string(RUSTG_HASH_MD5, thing))
+#endif
+
+// Text Operations //
+#define rustg_cyrillic_to_latin(text) RUSTG_CALL(RUST_G, "cyrillic_to_latin")("[text]")
+#define rustg_latin_to_cyrillic(text) RUSTG_CALL(RUST_G, "latin_to_cyrillic")("[text]")
+
+#define TTS_CATEGORY_OTHER "Другое"
+#define TTS_CATEGORY_WARCRAFT3 "WarCraft 3"
+#define TTS_CATEGORY_HALFLIFE2 "Half-Life 2"
+#define TTS_CATEGORY_STARCRAFT "StarCraft"
+#define TTS_CATEGORY_PORTAL2 "Portal 2"
+#define TTS_CATEGORY_STALKER "STALKER"
+#define TTS_CATEGORY_DOTA2 "Dota 2"
+#define TTS_CATEGORY_LOL "League of Legends"
+#define TTS_CATEGORY_FALLOUT "Fallout"
+#define TTS_CATEGORY_FALLOUT2 "Fallout 2"
+#define TTS_CATEGORY_POSTAL2 "Postal 2"
+#define TTS_CATEGORY_TEAMFORTRESS2 "Team Fortress 2"
+#define TTS_CATEGORY_ATOMIC_HEART "Atomic Heart"
+#define TTS_CATEGORY_OVERWATCH "Overwatch"
+#define TTS_CATEGORY_SKYRIM "Skyrim"
+#define TTS_CATEGORY_RITA "Rita"
+#define TTS_CATEGORY_METRO "Metro"
+#define TTS_CATEGORY_HEROESOFTHESTORM "Heroes of the Storm"
+#define TTS_CATEGORY_HEARTHSTONE "Hearthstone"
+#define TTS_CATEGORY_VALORANT "Valorant"
+#define TTS_CATEGORY_EVILISLANDS "Evil Islands"
+
+#define TTS_GENDER_ANY "Любой"
+#define TTS_GENDER_MALE "Мужской"
+#define TTS_GENDER_FEMALE "Женский"
+
+#define TTS_PHRASES list(\
+ "Так звучит мой голос.",\
+ "Так я звучу.",\
+ "Я.",\
+ "Поставьте свою подпись.",\
+ "Пора за работу.",\
+ "Дело сделано.",\
+ "Станция Нанотрейзен.",\
+ "Офицер СБ.",\
+ "Капитан.",\
+ "Вульпканин.",\
+ "Съешь же ещё этих мягких французских булок, да выпей чаю.",\
+ "Клоун, прекрати разбрасывать банановые кожурки офицерам под ноги!",\
+ "Капитан, вы уверены что хотите назначить клоуна на должность главы персонала?",\
+ )
+
+#define LOCAL_TTS_VOLUME(mob) mob.client.prefs.read_preference(/datum/preference/numeric/sound_tts_local)
+#define RADIO_TTS_VOLUME(mob) mob.client.prefs.read_preference(/datum/preference/numeric/sound_tts_radio)
+#define LOCAL_TTS_ENABLED(mob) LOCAL_TTS_VOLUME(mob)
+#define RADIO_TTS_ENABLED(mob) RADIO_TTS_VOLUME(mob)
+
+/proc/error(msg)
+ log_world("## ERROR: [msg]")
diff --git a/modular_ss220/modules/tts/code/providers/silero.dm b/modular_ss220/modules/tts/code/providers/silero.dm
new file mode 100644
index 000000000000000..69a3788d5a158b4
--- /dev/null
+++ b/modular_ss220/modules/tts/code/providers/silero.dm
@@ -0,0 +1,57 @@
+/datum/tts_provider/silero
+ name = "Silero"
+ is_enabled = TRUE
+
+/datum/tts_provider/silero/request(text, datum/tts_seed/silero/seed, datum/callback/proc_callback)
+ if(throttle_check())
+ return FALSE
+
+ var/api_url = "https://api-tts.silero.ai/voice"
+ var/ssml_text = {"[text] "}
+
+ var/list/req_body = list()
+ req_body["api_token"] = CONFIG_GET(string/tts_token_silero)
+ req_body["text"] = ssml_text
+ req_body["sample_rate"] = 24000
+ req_body["ssml"] = TRUE
+ req_body["speaker"] = seed.value
+ req_body["lang"] = "ru"
+ req_body["remote_id"] = "[world.port]"
+ req_body["put_accent"] = TRUE
+ req_body["put_yo"] = FALSE
+ req_body["symbol_durs"] = list()
+ req_body["format"] = "ogg"
+ req_body["word_ts"] = FALSE
+ // var/json_body = json_encode(req_body)
+ // log_debug(json_body)
+
+ var/datum/http_request/request = new()
+ request.prepare(RUSTG_HTTP_METHOD_POST, api_url, json_encode(req_body), list("content-type" = "application/json"))
+ spawn(0)
+ request.begin_async()
+ UNTIL(request.is_complete())
+ var/datum/http_response/response = request.into_response()
+ proc_callback.Invoke(response)
+
+ return TRUE
+
+/datum/tts_provider/silero/process_response(datum/http_response/response)
+ var/data = json_decode(response.body)
+ // log_debug(response.body)
+
+ if(data["timings"]["003_tts_time"] > 3)
+ is_throttled = TRUE
+ throttled_until = world.time + 15 SECONDS
+
+ return data["results"][1]["audio"]
+
+ //var/sha1 = data["original_sha1"]
+
+/datum/tts_provider/silero/pitch_whisper(text)
+ return {"[text] "}
+
+/datum/tts_provider/silero/rate_faster(text)
+ return {"[text] "}
+
+/datum/tts_provider/silero/rate_medium(text)
+ return {"[text] "}
diff --git a/modular_ss220/modules/tts/code/seeds/silero.dm b/modular_ss220/modules/tts/code/seeds/silero.dm
new file mode 100644
index 000000000000000..789f5503e205f58
--- /dev/null
+++ b/modular_ss220/modules/tts/code/seeds/silero.dm
@@ -0,0 +1,3357 @@
+/datum/tts_seed/silero
+ provider = /datum/tts_provider/silero
+
+/datum/tts_seed/silero/arthas
+ name = "Arthas"
+ value = "arthas"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/kelthuzad
+ name = "Kelthuzad"
+ value = "kelthuzad"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/anubarak
+ name = "Anubarak"
+ value = "anubarak"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/thrall
+ name = "Thrall"
+ value = "thrall"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/grunt
+ name = "Grunt"
+ value = "grunt"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/cairne
+ name = "Cairne"
+ value = "cairne"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/rexxar
+ name = "Rexxar"
+ value = "rexxar"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/uther
+ name = "Uther"
+ value = "uther"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/jaina
+ name = "Jaina"
+ value = "jaina"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/kael
+ name = "Kael"
+ value = "kael"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/garithos
+ name = "Garithos"
+ value = "garithos"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/maiev
+ name = "Maiev"
+ value = "maiev"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/naisha
+ name = "Naisha"
+ value = "naisha"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/tyrande
+ name = "Tyrande"
+ value = "tyrande"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/furion
+ name = "Furion"
+ value = "furion"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/illidan
+ name = "Illidan"
+ value = "illidan"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/ladyvashj
+ name = "Ladyvashj"
+ value = "ladyvashj"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/narrator
+ name = "Narrator"
+ value = "narrator"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/medivh
+ name = "Medivh"
+ value = "medivh"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/villagerm
+ name = "Villagerm"
+ value = "villagerm"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/xenia
+ name = "Xenia"
+ value = "xenia"
+ category = TTS_CATEGORY_OTHER
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/illidan_f
+ name = "Illidan_f"
+ value = "illidan_f"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/peon
+ name = "Peon"
+ value = "peon"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/chen
+ name = "Chen"
+ value = "chen"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/dread_bm
+ name = "Dread_bm"
+ value = "dread_bm"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sylvanas
+ name = "Sylvanas"
+ value = "sylvanas"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/priest
+ name = "Priest"
+ value = "priest"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/acolyte
+ name = "Acolyte"
+ value = "acolyte"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/muradin
+ name = "Muradin"
+ value = "muradin"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/dread_t
+ name = "Dread_t"
+ value = "dread_t"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/mannoroth
+ name = "Mannoroth"
+ value = "mannoroth"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sorceress
+ name = "Sorceress"
+ value = "sorceress"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/peasant
+ name = "Peasant"
+ value = "peasant"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/alyx
+ name = "Alyx"
+ value = "alyx"
+ category = TTS_CATEGORY_HALFLIFE2
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/glados
+ name = "Glados"
+ value = "glados"
+ category = TTS_CATEGORY_PORTAL2
+ gender = TTS_GENDER_ANY
+
+/datum/tts_seed/silero/announcer
+ name = "Announcer"
+ value = "announcer"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/wheatley
+ name = "Wheatley"
+ value = "wheatley"
+ category = TTS_CATEGORY_PORTAL2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/barney
+ name = "Barney"
+ value = "barney"
+ category = TTS_CATEGORY_HALFLIFE2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/raynor
+ name = "Raynor"
+ value = "raynor"
+ category = TTS_CATEGORY_STARCRAFT
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/kerrigan
+ name = "Kerrigan"
+ value = "kerrigan"
+ category = TTS_CATEGORY_STARCRAFT
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/tusk
+ name = "Tusk"
+ value = "tusk"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/earth
+ name = "Earth"
+ value = "earth"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/wraith
+ name = "Wraith"
+ value = "wraith"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/meepo
+ name = "Meepo"
+ value = "meepo"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_ANY
+
+/datum/tts_seed/silero/lina
+ name = "Lina"
+ value = "lina"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/bristle
+ name = "Bristle"
+ value = "bristle"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/gyro
+ name = "Gyro"
+ value = "gyro"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/treant
+ name = "Treant"
+ value = "treant"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/lancer
+ name = "Lancer"
+ value = "lancer"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/clockwerk
+ name = "Clockwerk"
+ value = "clockwerk"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/batrider
+ name = "Batrider"
+ value = "batrider"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/kotl
+ name = "Kotl"
+ value = "kotl"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/kunkka
+ name = "Kunkka"
+ value = "kunkka"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/pudge
+ name = "Pudge"
+ value = "pudge"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/juggernaut
+ name = "Juggernaut"
+ value = "juggernaut"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/vort_e2
+ name = "Vort_e2"
+ value = "vort_e2"
+ category = TTS_CATEGORY_HALFLIFE2
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/luna
+ name = "Luna"
+ value = "luna"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/omni
+ name = "Omni"
+ value = "omni"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sniper
+ name = "Sniper"
+ value = "sniper"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/skywrath
+ name = "Skywrath"
+ value = "skywrath"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/bounty
+ name = "Bounty"
+ value = "bounty"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_ANY
+
+/datum/tts_seed/silero/huskar
+ name = "Huskar"
+ value = "huskar"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/windranger
+ name = "Windranger"
+ value = "windranger"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/bloodseeker
+ name = "Bloodseeker"
+ value = "bloodseeker"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/templar
+ name = "Templar"
+ value = "templar"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/ranger
+ name = "Ranger"
+ value = "ranger"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/shaker
+ name = "Shaker"
+ value = "shaker"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/mortred
+ name = "Mortred"
+ value = "mortred"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/queen
+ name = "Queen"
+ value = "queen"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/storm
+ name = "Storm"
+ value = "storm"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/tide
+ name = "Tide"
+ value = "tide"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/evelynn
+ name = "Evelynn"
+ value = "evelynn"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 4
+
+/datum/tts_seed/silero/riki
+ name = "Riki"
+ value = "riki"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/antimage
+ name = "Antimage"
+ value = "antimage"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_ANY
+
+/datum/tts_seed/silero/witchdoctor
+ name = "Witchdoctor"
+ value = "witchdoctor"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/doom
+ name = "Doom"
+ value = "doom"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/yuumi
+ name = "Yuumi"
+ value = "yuumi"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_ANY
+
+/datum/tts_seed/silero/bandit
+ name = "Bandit"
+ value = "bandit"
+ category = TTS_CATEGORY_STALKER
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/pantheon
+ name = "pantheon"
+ value = "pantheon"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 4
+
+/datum/tts_seed/silero/tychus
+ name = "Tychus"
+ value = "tychus"
+ category = TTS_CATEGORY_STARCRAFT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/breen
+ name = "Breen"
+ value = "breen"
+ category = TTS_CATEGORY_HALFLIFE2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/kleiner
+ name = "Kleiner"
+ value = "kleiner"
+ category = TTS_CATEGORY_HALFLIFE2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/father
+ name = "Father"
+ value = "father"
+ category = TTS_CATEGORY_HALFLIFE2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/tosh
+ name = "Tosh"
+ value = "tosh"
+ category = TTS_CATEGORY_STARCRAFT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/stetmann
+ name = "Stetmann"
+ value = "stetmann"
+ category = TTS_CATEGORY_STARCRAFT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/hanson
+ name = "Hanson"
+ value = "hanson"
+ category = TTS_CATEGORY_STARCRAFT
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/swann
+ name = "Swann"
+ value = "swann"
+ category = TTS_CATEGORY_STARCRAFT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/hill
+ name = "Hill"
+ value = "hill"
+ category = TTS_CATEGORY_STARCRAFT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/gman_e2
+ name = "Gman_e2"
+ value = "gman_e2"
+ category = TTS_CATEGORY_HALFLIFE2
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/valerian
+ name = "Valerian"
+ value = "valerian"
+ category = TTS_CATEGORY_STARCRAFT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/gman
+ name = "Gman"
+ value = "gman"
+ category = TTS_CATEGORY_HALFLIFE2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/vort
+ name = "Vort"
+ value = "vort"
+ category = TTS_CATEGORY_HALFLIFE2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/aradesh
+ name = "Aradesh"
+ value = "aradesh"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/dornan
+ name = "Dornan"
+ value = "dornan"
+ category = TTS_CATEGORY_FALLOUT2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/elder
+ name = "Elder"
+ value = "elder"
+ category = TTS_CATEGORY_FALLOUT2
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/harris
+ name = "Harris"
+ value = "harris"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/cabbot
+ name = "Cabbot"
+ value = "cabbot"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/decker
+ name = "Decker"
+ value = "decker"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/dick
+ name = "Dick"
+ value = "dick"
+ category = TTS_CATEGORY_FALLOUT2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/officer
+ name = "Officer"
+ value = "officer"
+ category = TTS_CATEGORY_FALLOUT2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/frank
+ name = "Frank"
+ value = "frank"
+ category = TTS_CATEGORY_FALLOUT2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/gizmo
+ name = "Gizmo"
+ value = "gizmo"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/hakunin
+ name = "Hakunin"
+ value = "hakunin"
+ category = TTS_CATEGORY_FALLOUT2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/harold
+ name = "Harold"
+ value = "harold"
+ category = TTS_CATEGORY_FALLOUT2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/harry
+ name = "Harry"
+ value = "harry"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/jain
+ name = "Jain"
+ value = "jain"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/maxson
+ name = "Maxson"
+ value = "maxson"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/killian
+ name = "Killian"
+ value = "killian"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/laura
+ name = "Laura"
+ value = "laura"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/lieutenant
+ name = "Lieutenant"
+ value = "lieutenant"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/loxley
+ name = "Loxley"
+ value = "loxley"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/lynette
+ name = "Lynette"
+ value = "lynette"
+ category = TTS_CATEGORY_FALLOUT2
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/marcus
+ name = "Marcus"
+ value = "marcus"
+ category = TTS_CATEGORY_FALLOUT2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/master
+ name = "Master"
+ value = "master"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/morpheus
+ name = "Morpheus"
+ value = "morpheus"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/myron
+ name = "Myron"
+ value = "myron"
+ category = TTS_CATEGORY_FALLOUT2
+ gender = TTS_GENDER_ANY
+
+/datum/tts_seed/silero/nicole
+ name = "Nicole"
+ value = "nicole"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/overseer
+ name = "Overseer"
+ value = "overseer"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/rhombus
+ name = "Rhombus"
+ value = "rhombus"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/_set
+ name = "Set"
+ value = "set"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sulik
+ name = "Sulik"
+ value = "sulik"
+ category = TTS_CATEGORY_FALLOUT2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/tandi
+ name = "Tandi"
+ value = "tandi"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/vree
+ name = "Vree"
+ value = "vree"
+ category = TTS_CATEGORY_FALLOUT
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/dude
+ name = "Dude"
+ value = "dude"
+ category = TTS_CATEGORY_POSTAL2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/archmage
+ name = "Archmage"
+ value = "archmage"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/demoman
+ name = "Demoman"
+ value = "demoman"
+ category = TTS_CATEGORY_TEAMFORTRESS2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/engineer
+ name = "Engineer"
+ value = "engineer"
+ category = TTS_CATEGORY_TEAMFORTRESS2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/heavy
+ name = "Heavy"
+ value = "heavy"
+ category = TTS_CATEGORY_TEAMFORTRESS2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/medic
+ name = "Medic"
+ value = "medic"
+ category = TTS_CATEGORY_TEAMFORTRESS2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/scout
+ name = "Scout"
+ value = "scout"
+ category = TTS_CATEGORY_TEAMFORTRESS2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sniper_tf
+ name = "Sniper_tf"
+ value = "sniper_tf"
+ category = TTS_CATEGORY_TEAMFORTRESS2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/soldier
+ name = "Soldier"
+ value = "soldier"
+ category = TTS_CATEGORY_TEAMFORTRESS2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/spy
+ name = "Spy"
+ value = "spy"
+ category = TTS_CATEGORY_TEAMFORTRESS2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/admiral
+ name = "Admiral"
+ value = "admiral"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/alchemist
+ name = "Alchemist"
+ value = "alchemist"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/archimonde
+ name = "Archimonde"
+ value = "archimonde"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/breaker
+ name = "Breaker"
+ value = "breaker"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/captain
+ name = "Captain"
+ value = "captain"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/dryad
+ name = "Dryad"
+ value = "dryad"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_ANY
+
+/datum/tts_seed/silero/elf_eng
+ name = "Elf_eng"
+ value = "elf_eng"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/footman
+ name = "Footman"
+ value = "footman"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/grom
+ name = "Grom"
+ value = "grom"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/hh
+ name = "Hh"
+ value = "hh"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/huntress
+ name = "Huntress"
+ value = "huntress"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/keeper
+ name = "Keeper"
+ value = "keeper"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/naga_m
+ name = "Naga_m"
+ value = "naga_m"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/naga_rg
+ name = "Naga_rg"
+ value = "naga_rg"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/peasant_w
+ name = "Peasant_w"
+ value = "peasant_w"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/rifleman
+ name = "Rifleman"
+ value = "rifleman"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/satyr
+ name = "Satyr"
+ value = "satyr"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sylvanas_w
+ name = "Sylvanas_w"
+ value = "sylvanas_w"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/voljin
+ name = "Voljin"
+ value = "voljin"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sidorovich
+ name = "Sidorovich"
+ value = "sidorovich"
+ category = TTS_CATEGORY_STALKER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/p3
+ name = "P3"
+ value = "p3"
+ category = TTS_CATEGORY_ATOMIC_HEART
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/hraz
+ name = "Hraz"
+ value = "hraz"
+ category = TTS_CATEGORY_ATOMIC_HEART
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/tereshkova
+ name = "Tereshkova"
+ value = "tereshkova"
+ category = TTS_CATEGORY_ATOMIC_HEART
+ gender = TTS_GENDER_FEMALE
+ donator_level = 4
+
+/datum/tts_seed/silero/babazina
+ name = "Babazina"
+ value = "babazina"
+ category = TTS_CATEGORY_ATOMIC_HEART
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/darius
+ name = "Darius"
+ value = "darius"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/trundle
+ name = "Trundle"
+ value = "trundle"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/garen
+ name = "Garen"
+ value = "garen"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/kled
+ name = "Kled"
+ value = "kled"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/ekko
+ name = "Ekko"
+ value = "ekko"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/volibear
+ name = "Volibear"
+ value = "volibear"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/samira
+ name = "Samira"
+ value = "samira"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/swain
+ name = "Swain"
+ value = "swain"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/udyr
+ name = "Udyr"
+ value = "udyr"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/dr_mundo
+ name = "Dr_mundo"
+ value = "dr_mundo"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/graves
+ name = "Graves"
+ value = "graves"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/rakan
+ name = "Rakan"
+ value = "rakan"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/renata_glasc
+ name = "Renata_glasc"
+ value = "renata_glasc"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/gangplank
+ name = "Gangplank"
+ value = "gangplank"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/riven
+ name = "Riven"
+ value = "riven"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/katarina
+ name = "Katarina"
+ value = "katarina"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/ahri
+ name = "Ahri"
+ value = "ahri"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/ornn
+ name = "Ornn"
+ value = "ornn"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/braum
+ name = "Braum"
+ value = "braum"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/fizz
+ name = "Fizz"
+ value = "fizz"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/draven
+ name = "Draven"
+ value = "draven"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/qiyana
+ name = "Qiyana"
+ value = "qiyana"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/ksante
+ name = "Ksante"
+ value = "ksante"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/talon
+ name = "Talon"
+ value = "talon"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/shyvana
+ name = "Shyvana"
+ value = "shyvana"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/zenyatta
+ name = "Zenyatta"
+ value = "zenyatta"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/kiriko
+ name = "Kiriko"
+ value = "kiriko"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/hanzo
+ name = "Hanzo"
+ value = "hanzo"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 4
+
+/datum/tts_seed/silero/roadhog
+ name = "Roadhog"
+ value = "roadhog"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/sigma
+ name = "Sigma"
+ value = "sigma"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/soldier_76
+ name = "Soldier_76"
+ value = "soldier_76"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/junkrat
+ name = "Junkrat"
+ value = "junkrat"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/tracer
+ name = "Tracer"
+ value = "tracer"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/genji
+ name = "Genji"
+ value = "genji"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 4
+
+/datum/tts_seed/silero/echo
+ name = "Echo"
+ value = "echo"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/sojourn
+ name = "Sojourn"
+ value = "sojourn"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/winston
+ name = "Winston"
+ value = "winston"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/reaper
+ name = "Reaper"
+ value = "reaper"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/training_robot
+ name = "Training_robot"
+ value = "training_robot"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/m_darkelf
+ name = "M_darkelf"
+ value = "m_darkelf"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/esbern
+ name = "Esbern"
+ value = "esbern"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/m_argo
+ name = "M_argo"
+ value = "m_argo"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/m_khajiit
+ name = "M_khajiit"
+ value = "m_khajiit"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/m_coward
+ name = "M_coward"
+ value = "m_coward"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/farkas
+ name = "Farkas"
+ value = "farkas"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/m_drunk
+ name = "M_drunk"
+ value = "m_drunk"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/f_khajiit
+ name = "F_khajiit"
+ value = "f_khajiit"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/m_citizen
+ name = "M_citizen"
+ value = "m_citizen"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/m_orc
+ name = "M_orc"
+ value = "m_orc"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/odahviing
+ name = "Odahviing"
+ value = "odahviing"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/kodlak
+ name = "Kodlak"
+ value = "kodlak"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/m_child
+ name = "M_child"
+ value = "m_child"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/emperor
+ name = "Emperor"
+ value = "emperor"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/hagraven
+ name = "Hagraven"
+ value = "hagraven"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/nazir
+ name = "Nazir"
+ value = "nazir"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/dremora
+ name = "Dremora"
+ value = "dremora"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/alduin
+ name = "Alduin"
+ value = "alduin"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/malkoran
+ name = "Malkoran"
+ value = "malkoran"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/barbas
+ name = "Barbas"
+ value = "barbas"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/hermaeus
+ name = "Hermaeus"
+ value = "hermaeus"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 4
+
+/datum/tts_seed/silero/hakon
+ name = "Hakon"
+ value = "hakon"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/rita
+ name = "Rita"
+ value = "rita"
+ category = TTS_CATEGORY_RITA
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/barman
+ name = "Barman"
+ value = "barman"
+ category = TTS_CATEGORY_STALKER
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/bridger2
+ name = "Bridger2"
+ value = "bridger2"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/bridger3
+ name = "Bridger3"
+ value = "bridger3"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/cannibal3
+ name = "Cannibal3"
+ value = "cannibal3"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/bridger1
+ name = "Bridger1"
+ value = "bridger1"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/cannibal2
+ name = "Cannibal2"
+ value = "cannibal2"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/slave1
+ name = "Slave1"
+ value = "slave1"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/slave3
+ name = "Slave3"
+ value = "slave3"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/mira
+ name = "Mira"
+ value = "mira"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/valeera
+ name = "Valeera"
+ value = "valeera"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/rehgar
+ name = "Rehgar"
+ value = "rehgar"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/yrel
+ name = "Yrel"
+ value = "yrel"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/volskaya
+ name = "Volskaya"
+ value = "volskaya"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/necromancer
+ name = "Necromancer"
+ value = "necromancer"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/zuljin
+ name = "Zuljin"
+ value = "zuljin"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/samuro
+ name = "Samuro"
+ value = "samuro"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/tyrael
+ name = "Tyrael"
+ value = "tyrael"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/athena
+ name = "Athena"
+ value = "athena"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/default
+ name = "Default"
+ value = "default"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/chromie
+ name = "Chromie"
+ value = "chromie"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/orphea
+ name = "Orphea"
+ value = "orphea"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/adjutant
+ name = "Adjutant"
+ value = "adjutant"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/vanndara
+ name = "Vanndara"
+ value = "vanndara"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/mechatassadar
+ name = "Mechatassadar"
+ value = "mechatassadar"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/blackheart
+ name = "Blackheart"
+ value = "blackheart"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/olaf
+ name = "Olaf"
+ value = "olaf"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/alarak
+ name = "Alarak"
+ value = "alarak"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/dva
+ name = "Dva"
+ value = "dva"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/toy18
+ name = "Toy18"
+ value = "toy18"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/witchdoctor_h
+ name = "Witchdoctor_h"
+ value = "witchdoctor_h"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/lucio
+ name = "Lucio"
+ value = "lucio"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/angel
+ name = "Angel"
+ value = "angel"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/thunderking
+ name = "Thunderking"
+ value = "thunderking"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/dr_boom
+ name = "Dr_boom"
+ value = "dr_boom"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/hooktusk
+ name = "Hooktusk"
+ value = "hooktusk"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/sinclari
+ name = "Sinclari"
+ value = "sinclari"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/kazakus
+ name = "Kazakus"
+ value = "kazakus"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/ol_toomba
+ name = "Ol_toomba"
+ value = "ol_toomba"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/moroes
+ name = "Moroes"
+ value = "moroes"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/maiev_hs
+ name = "Maiev_hs"
+ value = "maiev_hs"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/zentimo
+ name = "Zentimo"
+ value = "zentimo"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/rastakhan
+ name = "Rastakhan"
+ value = "rastakhan"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/innkeeper
+ name = "Innkeeper"
+ value = "innkeeper"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/togwaggle
+ name = "Togwaggle"
+ value = "togwaggle"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/biggs
+ name = "Biggs"
+ value = "biggs"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/brann
+ name = "Brann"
+ value = "brann"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/tekahn_boss
+ name = "Tekahn_boss"
+ value = "tekahn_boss"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/siamat
+ name = "Siamat"
+ value = "siamat"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/omnotron
+ name = "Omnotron"
+ value = "omnotron"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/putricide
+ name = "Putricide"
+ value = "putricide"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/khadgar
+ name = "Khadgar"
+ value = "khadgar"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/zoie
+ name = "Zoie"
+ value = "zoie"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/azalina
+ name = "Azalina"
+ value = "azalina"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/chu
+ name = "Chu"
+ value = "chu"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/tekahn
+ name = "Tekahn"
+ value = "tekahn"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/sthara
+ name = "Sthara"
+ value = "sthara"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/dovo
+ name = "Dovo"
+ value = "dovo"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 4
+
+/datum/tts_seed/silero/shaw
+ name = "Shaw"
+ value = "shaw"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/greymane
+ name = "Greymane"
+ value = "greymane"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/willow
+ name = "Willow"
+ value = "willow"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/haro
+ name = "Haro"
+ value = "haro"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/hagatha
+ name = "Hagatha"
+ value = "hagatha"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/reno
+ name = "Reno"
+ value = "reno"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/ozara
+ name = "Ozara"
+ value = "ozara"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/loti
+ name = "Loti"
+ value = "loti"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/tarkus
+ name = "Tarkus"
+ value = "tarkus"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/voone
+ name = "Voone"
+ value = "voone"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/tala
+ name = "Tala"
+ value = "tala"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/edra
+ name = "Edra"
+ value = "edra"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/myra
+ name = "Myra"
+ value = "myra"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/smiggs
+ name = "Smiggs"
+ value = "smiggs"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/timothy
+ name = "Timothy"
+ value = "timothy"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/wendy
+ name = "Wendy"
+ value = "wendy"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/hannigan
+ name = "Hannigan"
+ value = "hannigan"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/vargoth
+ name = "Vargoth"
+ value = "vargoth"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/jolene
+ name = "Jolene"
+ value = "jolene"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/kyriss
+ name = "Kyriss"
+ value = "kyriss"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/saurfang
+ name = "Saurfang"
+ value = "saurfang"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/kizi
+ name = "Kizi"
+ value = "kizi"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/slate
+ name = "Slate"
+ value = "slate"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/hesutu
+ name = "Hesutu"
+ value = "hesutu"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/hancho
+ name = "Hancho"
+ value = "hancho"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/gnomenapper
+ name = "Gnomenapper"
+ value = "gnomenapper"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/valdera
+ name = "Valdera"
+ value = "valdera"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/disidra
+ name = "Disidra"
+ value = "disidra"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/omu
+ name = "Omu"
+ value = "omu"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/floop
+ name = "Floop"
+ value = "floop"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 4
+
+/datum/tts_seed/silero/belloc
+ name = "Belloc"
+ value = "belloc"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/xurios
+ name = "Xurios"
+ value = "xurios"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/wagtoggle
+ name = "Wagtoggle"
+ value = "wagtoggle"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/belnaara
+ name = "Belnaara"
+ value = "belnaara"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/lilayell
+ name = "Lilayell"
+ value = "lilayell"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/candlebeard
+ name = "Candlebeard"
+ value = "candlebeard"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/awilo
+ name = "Awilo"
+ value = "awilo"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/marei
+ name = "Marei"
+ value = "marei"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/applebough
+ name = "Applebough"
+ value = "applebough"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/lazul
+ name = "Lazul"
+ value = "lazul"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/arwyn
+ name = "Arwyn"
+ value = "arwyn"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/glowtron
+ name = "Glowtron"
+ value = "glowtron"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/cardish
+ name = "Cardish"
+ value = "cardish"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/robold
+ name = "Robold"
+ value = "robold"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/malfurion
+ name = "Malfurion"
+ value = "malfurion"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/deathwhisper
+ name = "Deathwhisper"
+ value = "deathwhisper"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/janna
+ name = "Janna"
+ value = "janna"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/cassiopeia
+ name = "Cassiopeia"
+ value = "cassiopeia"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/taliyah
+ name = "Taliyah"
+ value = "taliyah"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/neeko
+ name = "Neeko"
+ value = "neeko"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/taric
+ name = "Taric"
+ value = "taric"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/akshan
+ name = "Akshan"
+ value = "akshan"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/tristana
+ name = "Tristana"
+ value = "tristana"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/sylas
+ name = "Sylas"
+ value = "sylas"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/sejuani
+ name = "Sejuani"
+ value = "sejuani"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/anivia
+ name = "Anivia"
+ value = "anivia"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/vayne
+ name = "Vayne"
+ value = "vayne"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/karma
+ name = "Karma"
+ value = "karma"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/nilah
+ name = "Nilah"
+ value = "nilah"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/olaf_lol
+ name = "Olaf_lol"
+ value = "olaf_lol"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/quinn
+ name = "Quinn"
+ value = "quinn"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/lissandra
+ name = "Lissandra"
+ value = "lissandra"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/hecarim
+ name = "Hecarim"
+ value = "hecarim"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/vi
+ name = "Vi"
+ value = "vi"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/zyra
+ name = "Zyra"
+ value = "zyra"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/zac
+ name = "Zac"
+ value = "zac"
+ category = TTS_CATEGORY_LOL
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/moira
+ name = "Moira"
+ value = "moira"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/ashe
+ name = "Ashe"
+ value = "ashe"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/brigitte
+ name = "Brigitte"
+ value = "brigitte"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/mercy
+ name = "Mercy"
+ value = "mercy"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/lucio_ov
+ name = "Lucio_ov"
+ value = "lucio_ov"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/dva_ov
+ name = "Dva_ov"
+ value = "dva_ov"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/symmetra
+ name = "Symmetra"
+ value = "symmetra"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/zarya
+ name = "Zarya"
+ value = "zarya"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/cassidy
+ name = "Cassidy"
+ value = "cassidy"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/baptiste
+ name = "Baptiste"
+ value = "baptiste"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/junker_queen
+ name = "Junker_queen"
+ value = "junker_queen"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/doomfist
+ name = "Doomfist"
+ value = "doomfist"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/pharah
+ name = "Pharah"
+ value = "pharah"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/sombra
+ name = "Sombra"
+ value = "sombra"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/ana
+ name = "Ana"
+ value = "ana"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/widowmaker
+ name = "Widowmaker"
+ value = "widowmaker"
+ category = TTS_CATEGORY_OVERWATCH
+ gender = TTS_GENDER_FEMALE
+ donator_level = 4
+
+/datum/tts_seed/silero/harbor
+ name = "Harbor"
+ value = "harbor"
+ category = TTS_CATEGORY_VALORANT
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/sage
+ name = "Sage"
+ value = "sage"
+ category = TTS_CATEGORY_VALORANT
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/brimstone
+ name = "Brimstone"
+ value = "brimstone"
+ category = TTS_CATEGORY_VALORANT
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/sova
+ name = "Sova"
+ value = "sova"
+ category = TTS_CATEGORY_VALORANT
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/f_shrill
+ name = "F_shrill"
+ value = "f_shrill"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/m_haughty
+ name = "M_haughty"
+ value = "m_haughty"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/m_soldier
+ name = "M_soldier"
+ value = "m_soldier"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/sven
+ name = "Sven"
+ value = "sven"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/f_sultry
+ name = "F_sultry"
+ value = "f_sultry"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/eorlund
+ name = "Eorlund"
+ value = "eorlund"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/m_commander
+ name = "M_commander"
+ value = "m_commander"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/f_nord
+ name = "F_nord"
+ value = "f_nord"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/lydia
+ name = "Lydia"
+ value = "lydia"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/motierre
+ name = "Motierre"
+ value = "motierre"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/f_haughty
+ name = "F_haughty"
+ value = "f_haughty"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/tullius
+ name = "Tullius"
+ value = "tullius"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/festus
+ name = "Festus"
+ value = "festus"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/m_nord
+ name = "M_nord"
+ value = "m_nord"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/olava
+ name = "Olava"
+ value = "olava"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/f_commander
+ name = "F_commander"
+ value = "f_commander"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/hadvar
+ name = "Hadvar"
+ value = "hadvar"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/f_argo
+ name = "F_argo"
+ value = "f_argo"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/arngeir
+ name = "Arngeir"
+ value = "arngeir"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/nazeem
+ name = "Nazeem"
+ value = "nazeem"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/falion
+ name = "Falion"
+ value = "falion"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/f_coward
+ name = "F_coward"
+ value = "f_coward"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/m_guard
+ name = "M_guard"
+ value = "m_guard"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/m_commoner
+ name = "M_commoner"
+ value = "m_commoner"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/elisif
+ name = "Elisif"
+ value = "elisif"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/paarthurnax
+ name = "Paarthurnax"
+ value = "paarthurnax"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/grelka
+ name = "Grelka"
+ value = "grelka"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/f_commoner
+ name = "F_commoner"
+ value = "f_commoner"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/ebony
+ name = "Ebony"
+ value = "ebony"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/ulfric
+ name = "Ulfric"
+ value = "ulfric"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/farengar
+ name = "Farengar"
+ value = "farengar"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/astrid
+ name = "Astrid"
+ value = "astrid"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/brynjolf
+ name = "Brynjolf"
+ value = "brynjolf"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/maven
+ name = "Maven"
+ value = "maven"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/f_child
+ name = "F_child"
+ value = "f_child"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/f_orc
+ name = "F_orc"
+ value = "f_orc"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/delphine
+ name = "Delphine"
+ value = "delphine"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/f_darkelf
+ name = "F_darkelf"
+ value = "f_darkelf"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/grelod
+ name = "Grelod"
+ value = "grelod"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/tolfdir
+ name = "Tolfdir"
+ value = "tolfdir"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/m_bandit
+ name = "M_bandit"
+ value = "m_bandit"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/m_forsworn
+ name = "M_forsworn"
+ value = "m_forsworn"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/karliah
+ name = "Karliah"
+ value = "karliah"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/felldir
+ name = "Felldir"
+ value = "felldir"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/ancano
+ name = "Ancano"
+ value = "ancano"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/mercer
+ name = "Mercer"
+ value = "mercer"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/vex
+ name = "Vex"
+ value = "vex"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/mirabelle
+ name = "Mirabelle"
+ value = "mirabelle"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/aventus
+ name = "Aventus"
+ value = "aventus"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/tsun
+ name = "Tsun"
+ value = "tsun"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/elenwen
+ name = "Elenwen"
+ value = "elenwen"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/gormlaith
+ name = "Gormlaith"
+ value = "gormlaith"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/dragon
+ name = "Dragon"
+ value = "dragon"
+ category = TTS_CATEGORY_SKYRIM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/overwatch
+ name = "Overwatch"
+ value = "overwatch"
+ category = TTS_CATEGORY_HALFLIFE2
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/zak
+ name = "Zak"
+ value = "zak"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/merc2
+ name = "Merc2"
+ value = "merc2"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/forest1
+ name = "Forest1"
+ value = "forest1"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/bandit3
+ name = "Bandit3"
+ value = "bandit3"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/forest2
+ name = "Forest2"
+ value = "forest2"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/merc1
+ name = "Merc1"
+ value = "merc1"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/bandit2
+ name = "Bandit2"
+ value = "bandit2"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/forest3
+ name = "Forest3"
+ value = "forest3"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/tribal3
+ name = "Tribal3"
+ value = "tribal3"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/slave2
+ name = "Slave2"
+ value = "slave2"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/miller
+ name = "Miller"
+ value = "miller"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/krest
+ name = "Krest"
+ value = "krest"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/tribal1
+ name = "Tribal1"
+ value = "tribal1"
+ category = TTS_CATEGORY_METRO
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/abathur
+ name = "Abathur"
+ value = "abathur"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/erik
+ name = "Erik"
+ value = "erik"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/varian
+ name = "Varian"
+ value = "varian"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/anduin
+ name = "Anduin"
+ value = "anduin"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/deckard
+ name = "Deckard"
+ value = "deckard"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/malfurion_h
+ name = "Malfurion_h"
+ value = "malfurion_h"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 4
+
+/datum/tts_seed/silero/demonhunter
+ name = "Demonhunter"
+ value = "demonhunter"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/demon
+ name = "Demon"
+ value = "demon"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/kerrigan_h
+ name = "Kerrigan_h"
+ value = "kerrigan_h"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/ladyofthorns
+ name = "Ladyofthorns"
+ value = "ladyofthorns"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/barbarian
+ name = "Barbarian"
+ value = "barbarian"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/crusader
+ name = "Crusader"
+ value = "crusader"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/whitemane
+ name = "Whitemane"
+ value = "whitemane"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/nexushunter
+ name = "Nexushunter"
+ value = "nexushunter"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/greymane_h
+ name = "Greymane_h"
+ value = "greymane_h"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/gardensdayannouncer
+ name = "Gardensdayannouncer"
+ value = "gardensdayannouncer"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/drekthar
+ name = "Drekthar"
+ value = "drekthar"
+ category = TTS_CATEGORY_HEROESOFTHESTORM
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/squeamlish
+ name = "Squeamlish"
+ value = "squeamlish"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/dagg
+ name = "Dagg"
+ value = "dagg"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/brukan
+ name = "Brukan"
+ value = "brukan"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/bolan
+ name = "Bolan"
+ value = "bolan"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/goya
+ name = "Goya"
+ value = "goya"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/stargazer
+ name = "Stargazer"
+ value = "stargazer"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/eudora
+ name = "Eudora"
+ value = "eudora"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/mozaki
+ name = "Mozaki"
+ value = "mozaki"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/katrana
+ name = "Katrana"
+ value = "katrana"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/valeera_hs
+ name = "Valeera_hs"
+ value = "valeera_hs"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/malacrass
+ name = "Malacrass"
+ value = "malacrass"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/elise
+ name = "Elise"
+ value = "elise"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/flark
+ name = "Flark"
+ value = "flark"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/rhogi
+ name = "Rhogi"
+ value = "rhogi"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/gallywix
+ name = "Gallywix"
+ value = "gallywix"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/talanji
+ name = "Talanji"
+ value = "talanji"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/dr_sezavo
+ name = "Dr_sezavo"
+ value = "dr_sezavo"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/tierra
+ name = "Tierra"
+ value = "tierra"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/zenda
+ name = "Zenda"
+ value = "zenda"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/baechao
+ name = "Baechao"
+ value = "baechao"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/lilian
+ name = "Lilian"
+ value = "lilian"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/aranna
+ name = "Aranna"
+ value = "aranna"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/oshi
+ name = "Oshi"
+ value = "oshi"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/norroa
+ name = "Norroa"
+ value = "norroa"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/turalyon
+ name = "Turalyon"
+ value = "turalyon"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 2
+
+/datum/tts_seed/silero/aki
+ name = "Aki"
+ value = "aki"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/lunara
+ name = "Lunara"
+ value = "lunara"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/bob
+ name = "Bob"
+ value = "bob"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/illucia
+ name = "Illucia"
+ value = "illucia"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/yrel_hs
+ name = "Yrel_hs"
+ value = "yrel_hs"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/fireheart
+ name = "Fireheart"
+ value = "fireheart"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/lanathel
+ name = "Lanathel"
+ value = "lanathel"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/tyrande_hs
+ name = "Tyrande_hs"
+ value = "tyrande_hs"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/draemus
+ name = "Draemus"
+ value = "draemus"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/rasil
+ name = "Rasil"
+ value = "rasil"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/kalec
+ name = "Kalec"
+ value = "kalec"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/karastamper
+ name = "Karastamper"
+ value = "karastamper"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/george
+ name = "George"
+ value = "george"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/pollark
+ name = "Pollark"
+ value = "pollark"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/stelina
+ name = "Stelina"
+ value = "stelina"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/kasa
+ name = "Kasa"
+ value = "kasa"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 2
+
+/datum/tts_seed/silero/whirt
+ name = "Whirt"
+ value = "whirt"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 1
+
+/datum/tts_seed/silero/anarii
+ name = "Anarii"
+ value = "anarii"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/ilza
+ name = "Ilza"
+ value = "ilza"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/avozu
+ name = "Avozu"
+ value = "avozu"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_ANY
+ donator_level = 1
+
+/datum/tts_seed/silero/jeklik
+ name = "Jeklik"
+ value = "jeklik"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 1
+
+/datum/tts_seed/silero/zibb
+ name = "Zibb"
+ value = "zibb"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/thrud
+ name = "Thrud"
+ value = "thrud"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_MALE
+ donator_level = 3
+
+/datum/tts_seed/silero/isiset
+ name = "Isiset"
+ value = "isiset"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_FEMALE
+ donator_level = 3
+
+/datum/tts_seed/silero/akazamzarak
+ name = "Akazamzarak"
+ value = "akazamzarak"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_ANY
+ donator_level = 2
+
+/datum/tts_seed/silero/arha
+ name = "Arha"
+ value = "arha"
+ category = TTS_CATEGORY_HEARTHSTONE
+ gender = TTS_GENDER_ANY
+
+/datum/tts_seed/silero/aidar
+ name = "Aidar"
+ value = "aidar"
+ category = TTS_CATEGORY_OTHER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/baya
+ name = "Baya"
+ value = "baya"
+ category = TTS_CATEGORY_OTHER
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/kseniya
+ name = "Kseniya"
+ value = "kseniya"
+ category = TTS_CATEGORY_OTHER
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/eugene
+ name = "Eugene"
+ value = "eugene"
+ category = TTS_CATEGORY_OTHER
+ gender = TTS_GENDER_MALE
diff --git a/modular_ss220/modules/tts/code/tts_configuration.dm b/modular_ss220/modules/tts/code/tts_configuration.dm
new file mode 100644
index 000000000000000..cedf01f7f9c59c2
--- /dev/null
+++ b/modular_ss220/modules/tts/code/tts_configuration.dm
@@ -0,0 +1,11 @@
+/datum/config_entry/flag/tts_enabled
+ default = FALSE
+ protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
+
+/datum/config_entry/string/tts_token_silero
+ default = ""
+ protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
+
+/datum/config_entry/flag/tts_cache
+ default = FALSE
+ protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
diff --git a/modular_ss220/modules/tts/code/tts_mob_Hear.dm b/modular_ss220/modules/tts/code/tts_mob_Hear.dm
new file mode 100644
index 000000000000000..9d60041c6ca9e69
--- /dev/null
+++ b/modular_ss220/modules/tts/code/tts_mob_Hear.dm
@@ -0,0 +1,70 @@
+/mob/proc/Hear_tts(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods, message_range)
+ if(!SStts.is_enabled)
+ return
+
+ if(!isliving(src) && !isobserver(src))
+ return
+
+ if(!client)
+ return
+
+ if(HAS_TRAIT(speaker, TRAIT_SIGN_LANG))
+ return
+
+ if(!message_language)
+ return
+
+ var/is_custom_say_emote_without_message = (MODE_CUSTOM_SAY_ERASE_INPUT in message_mods)
+ if(is_custom_say_emote_without_message)
+ return
+
+ if(stat == UNCONSCIOUS || stat == HARD_CRIT)
+ return
+
+ if(!radio_freq && !LOCAL_TTS_ENABLED(src) || radio_freq && !RADIO_TTS_ENABLED(src))
+ return
+
+ var/atom/movable/virtualspeaker/virtual_speaker = speaker
+ var/atom/movable/real_speaker = istype(virtual_speaker) ? virtual_speaker.source : speaker
+
+ var/self_radio = radio_freq && src == real_speaker
+ if(self_radio)
+ return
+
+ var/is_speaker_whispering = (WHISPER_MODE in message_mods)
+ var/can_hear_whisper = get_dist(speaker, src) <= message_range || isobserver(src)
+ if(is_speaker_whispering && !can_hear_whisper)
+ return
+
+ var/effect = issilicon(real_speaker) ? SOUND_EFFECT_ROBOT : SOUND_EFFECT_NONE
+ if(radio_freq)
+ effect = issilicon(real_speaker) ? SOUND_EFFECT_RADIO_ROBOT : SOUND_EFFECT_RADIO
+ else if(SPAN_COMMAND in spans)
+ effect = issilicon(real_speaker) ? SOUND_EFFECT_MEGAPHONE_ROBOT : SOUND_EFFECT_MEGAPHONE
+
+ var/traits = TTS_TRAIT_RATE_MEDIUM
+ if(is_speaker_whispering)
+ traits &= TTS_TRAIT_PITCH_WHISPER
+
+ var/mob/living/carbon/human/human_speaker = real_speaker
+ var/tts_seed = istype(human_speaker) && human_speaker.tts_seed || "Arthas"
+
+ var/message_tts = translate_language(language = message_language, raw_message = raw_message)
+
+ INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(tts_cast), speaker, src, message_tts, tts_seed, !radio_freq, effect, traits)
+
+/mob/living/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods, message_range)
+ var/static/regex/plus_sign_replace = new(@"\+", "g")
+ var/plussless_message = plus_sign_replace.Replace(raw_message, "")
+
+ . = ..(message, speaker, message_language, plussless_message, radio_freq, spans, message_mods, message_range)
+
+ Hear_tts(message, speaker, message_language, raw_message, radio_freq, spans, message_mods, message_range)
+
+/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods, message_range)
+ var/static/regex/plus_sign_replace = new(@"\+", "g")
+ var/plussless_message = plus_sign_replace.Replace(raw_message, "")
+
+ . = ..(message, speaker, message_language, plussless_message, radio_freq, spans, message_mods, message_range)
+
+ Hear_tts(message, speaker, message_language, raw_message, radio_freq, spans, message_mods, message_range)
diff --git a/modular_ss220/modules/tts/code/tts_numbers.dm b/modular_ss220/modules/tts/code/tts_numbers.dm
new file mode 100644
index 000000000000000..c330ce48a285aff
--- /dev/null
+++ b/modular_ss220/modules/tts/code/tts_numbers.dm
@@ -0,0 +1,170 @@
+/proc/num_in_words(n)
+ return get_num_in_words(n)
+
+/proc/dec_in_words(n)
+ return get_num_in_words(n, TRUE)
+
+/proc/get_num_in_words(n, decimal = FALSE)
+ var/static/datum/number/num
+ if(!num)
+ num = new /datum/number
+
+ if(num.cache["[n]"])
+ return num.cache["[n]"]
+
+ var/result
+ if(decimal)
+ result = num.decimal2words(n)
+ else
+ result = num.int2words(n)
+
+ result = " [result] "
+ num.cache["[n]"] = result
+ return result
+
+/datum/number
+ var/static/list/units = list(
+ "ноль",
+
+ list("один", "одна"),
+ list("два", "две"),
+
+ "три", "четыре", "пять",
+ "шесть", "семь", "восемь", "девять"
+ )
+
+ var/static/list/teens = list(
+ "десять", "одиннадцать",
+ "двенадцать", "тринадцать",
+ "четырнадцать", "пятнадцать",
+ "шестнадцать", "семнадцать",
+ "восемнадцать", "девятнадцать"
+ )
+
+ var/static/list/tens = list(
+ "десять",
+ "двадцать", "тридцать",
+ "сорок", "пятьдесят",
+ "шестьдесят", "семьдесят",
+ "восемьдесят", "девяносто"
+ )
+
+ var/static/list/hundreds = list(
+ "сто", "двести",
+ "триста", "четыреста",
+ "пятьсот", "шестьсот",
+ "семьсот", "восемьсот",
+ "девятьсот"
+ )
+
+ var/static/list/orders = list(
+ list(list("тысяча", "тысячи", "тысяч"), "f"),
+ list(list("миллион", "миллиона", "миллионов"), "m"),
+ list(list("миллиард", "миллиарда", "миллиардов"), "m"),
+ list(list("триллион", "триллиона", "триллионов"), "m"),
+ list(list("квадриллион", "квадриллиона", "квадриллионов"), "m"),
+ list(list("квинтиллион", "квинтиллиона", "квинтиллионов"), "m"),
+ )
+
+ var/static/list/decimal_int_units = list(list("целая", "целых", "целых"), "f")
+
+ var/static/list/decimal_exp_units = list(
+ list(list("десятая", "десятых", "десятых"), "f"),
+ list(list("сотая", "сотых", "сотых"), "f"),
+ list(list("тысячная", "тысячных", "тысячных"), "f"),
+ )
+
+ var/static/minus = "минус"
+
+ var/static/cache = list()
+
+/datum/number/proc/thousand(rest, sex)
+// """Converts numbers from 19 to 999"""
+ var/prev = 0
+ var/plural = 3
+ var/list/name = list()
+ var/use_teens = (rest % 100 >= 10) && (rest % 100 <= 19)
+ var/list/data = list()
+
+ if(!use_teens)
+ data = list( list(units, 10), list(tens, 100), list(hundreds, 1000) )
+ else
+ data = list( list(teens, 10), list(hundreds, 1000) )
+ for(var/list in data)
+
+ var/names = list[1]
+ var/x = list[2]
+
+ var/cur = round(((rest - prev) % x) * 10 / x) + 1
+ prev = rest % x
+
+ if(x == 10 && use_teens)
+ plural = 3
+ name += teens[cur]
+ else if(cur == 1)
+ continue
+ else if(x == 10)
+ var/name_ = names[cur]
+ if(islist(name_))
+ name_ = name_[sex == "m" ? 1 : 2]
+ name += name_
+ if(cur >= 3 && cur <= 5)
+ plural = 2
+ else if(cur == 2)
+ plural = 1
+ else
+ plural = 3
+ else
+ name += names[cur-1]
+
+ return list(plural, name)
+
+/datum/number/proc/int2words(textnum, list/main_units = list(list("", "", ""), "m"))
+// http://ru.wikipedia.org/wiki/Gettext#.D0.9C.D0.BD.D0.BE.D0.B6.D0.B5.D1.81.D1.82.D0.B2.D0.B5.D0.BD.D0.BD.D1.8B.D0.B5_.D1.87.D0.B8.D1.81.D0.BB.D0.B0_2
+
+ var/list/_orders = list(main_units) + orders
+
+ var/num = text2num(textnum)
+ if(num == 0)
+ return trim(jointext(list(units[1], _orders[1][1][3]), " "))
+
+ var/negative = FALSE
+ if(num < 0)
+ negative = TRUE
+ textnum = copytext_char(textnum, 2, 0)
+
+ var/ord = 1
+ var/list/name = list()
+
+ while(textnum)
+ var/next_thousand = text2num(copytext_char(textnum, -3, 0))
+ var/list/thousand_result = thousand(next_thousand, _orders[ord][2])
+ var/plural = thousand_result[1]
+ var/list/nme = thousand_result[2]
+
+ if(length(nme) || ord == 1)
+ name += _orders[ord][1][plural]
+
+ name += nme
+ textnum = copytext_char(textnum, 1, -3)
+ ord += 1
+
+ if(negative)
+ name += minus
+
+ var/temp_name = name
+ name = list()
+ for(var/i = length_char(temp_name), i >= 1, i--)
+ name += temp_name[i]
+
+ var/result = trim(jointext(name, " "))
+ return result
+
+/datum/number/proc/decimal2words(textvalue, places = 3)
+ var/pieces = splittext_char(textvalue, ".")
+ var/integral = pieces[1]
+ var/exp = copytext_char(pieces[2], 1, places + 1)
+ var/list/exp_units = decimal_exp_units[length_char(exp)]
+
+ var/result = trim("[int2words(integral, decimal_int_units)] [int2words(exp, exp_units)]")
+ return result
diff --git a/modular_ss220/modules/tts/code/tts_preferences.dm b/modular_ss220/modules/tts/code/tts_preferences.dm
new file mode 100644
index 000000000000000..6253ff074d419e0
--- /dev/null
+++ b/modular_ss220/modules/tts/code/tts_preferences.dm
@@ -0,0 +1,73 @@
+/datum/preferences/ui_static_data(mob/user)
+ var/list/data = ..()
+
+ data["tts_enabled"] = CONFIG_GET(flag/tts_enabled)
+
+ var/list/providers = list()
+ for(var/_provider in SStts.tts_providers)
+ var/datum/tts_provider/provider = SStts.tts_providers[_provider]
+ providers += list(list(
+ "name" = provider.name,
+ "is_enabled" = provider.is_enabled,
+ ))
+ data["providers"] = providers
+
+ var/list/seeds = list()
+ for(var/_seed in SStts.tts_seeds)
+ var/datum/tts_seed/seed = SStts.tts_seeds[_seed]
+ seeds += list(list(
+ "name" = seed.name,
+ "value" = seed.value,
+ "category" = seed.category,
+ "gender" = seed.gender,
+ "provider" = initial(seed.provider.name),
+ "donator_level" = seed.donator_level,
+ ))
+ data["seeds"] = seeds
+
+ data["phrases"] = TTS_PHRASES
+
+ return data
+
+
+/datum/preferences/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if (.)
+ return
+
+ switch (action)
+ if("listen")
+ var/phrase = params["phrase"]
+ var/seed_name = params["seed"]
+
+ if((phrase in TTS_PHRASES) && (seed_name in SStts.tts_seeds))
+ INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(tts_cast), null, usr, phrase, seed_name, FALSE)
+ return FALSE
+
+ if("select_voice")
+ var/seed_name = params["seed"]
+ var/datum/preference/tts_seed = GLOB.preference_entries_by_key["tts_seed"]
+ write_preference(tts_seed, seed_name)
+ return TRUE
+
+/datum/preference/numeric/sound_tts_local
+ category = PREFERENCE_CATEGORY_GAME_PREFERENCES
+ savefile_key = "sound_tts_local"
+ savefile_identifier = PREFERENCE_PLAYER
+
+ minimum = 0
+ maximum = 100
+
+/datum/preference/numeric/sound_tts_local/create_default_value()
+ return 100
+
+/datum/preference/numeric/sound_tts_radio
+ category = PREFERENCE_CATEGORY_GAME_PREFERENCES
+ savefile_key = "sound_tts_radio"
+ savefile_identifier = PREFERENCE_PLAYER
+
+ minimum = 0
+ maximum = 100
+
+/datum/preference/numeric/sound_tts_radio/create_default_value()
+ return 50
diff --git a/modular_ss220/modules/tts/code/tts_provider.dm b/modular_ss220/modules/tts/code/tts_provider.dm
new file mode 100644
index 000000000000000..aa159eef07cde04
--- /dev/null
+++ b/modular_ss220/modules/tts/code/tts_provider.dm
@@ -0,0 +1,31 @@
+/datum/tts_provider
+ var/name = "STUB"
+ var/is_enabled = TRUE
+
+ // Throttling
+ var/is_throttled = FALSE
+ var/throttled_until = 0
+
+ var/failed_requests = 0
+ var/failed_requests_limit = 10
+
+/datum/tts_provider/proc/request(text, datum/tts_seed/seed, datum/callback/proc_callback)
+ return TRUE
+
+/datum/tts_provider/proc/process_response(datum/http_response/response)
+ return null
+
+/datum/tts_provider/proc/throttle_check()
+ if(is_throttled && throttled_until < world.time)
+ return TRUE
+ is_throttled = FALSE
+ return FALSE
+
+/datum/tts_provider/proc/pitch_whisper(text)
+ return text
+
+/datum/tts_provider/proc/rate_faster(text)
+ return text
+
+/datum/tts_provider/proc/rate_medium(text)
+ return text
diff --git a/modular_ss220/modules/tts/code/tts_seed.dm b/modular_ss220/modules/tts/code/tts_seed.dm
new file mode 100644
index 000000000000000..482275a3120c0bf
--- /dev/null
+++ b/modular_ss220/modules/tts/code/tts_seed.dm
@@ -0,0 +1,24 @@
+/datum/tts_seed
+ var/name = "STUB"
+ var/value = "STUB"
+ var/category = TTS_CATEGORY_OTHER
+ var/gender = TTS_GENDER_ANY
+ var/datum/tts_provider/provider = /datum/tts_provider
+ var/donator_level = 0
+
+/datum/tts_seed/vv_edit_var(var_name, var_value)
+ return FALSE
+
+/datum/preference/text/tts_seed
+ savefile_key = "tts_seed"
+ savefile_identifier = PREFERENCE_CHARACTER
+
+/datum/preference/text/tts_seed/create_default_value()
+ return "Arthas"
+
+/// Any humanoid (non-Xeno) mob, such as humans, plasmamen, lizards.
+/mob/living/carbon/human
+ var/tts_seed
+
+/datum/preference/text/tts_seed/apply_to_human(mob/living/carbon/human/target, value)
+ target.tts_seed = value
diff --git a/modular_ss220/modules/tts/code/tts_sound.dm b/modular_ss220/modules/tts/code/tts_sound.dm
new file mode 100644
index 000000000000000..148a73a55f55049
--- /dev/null
+++ b/modular_ss220/modules/tts/code/tts_sound.dm
@@ -0,0 +1,44 @@
+// TODO: SS220-TTS to delete
+//world/proc/shelleo
+#define SHELLEO_ERRORLEVEL 1
+#define SHELLEO_STDOUT 2
+#define SHELLEO_STDERR 3
+
+/proc/apply_sound_effect(effect, filename_input, filename_output)
+ if(!effect)
+ CRASH("Invalid sound effect chosen.")
+
+ var/taskset
+ // TODO: SS220-TTS
+ // if(GLOB.ffmpeg_cpuaffinity)
+ // taskset = "taskset -ac [GLOB.ffmpeg_cpuaffinity]"
+
+ var/list/output
+ switch(effect)
+ if(SOUND_EFFECT_RADIO)
+ output = world.shelleo({"[taskset] ffmpeg -y -hide_banner -loglevel error -i [filename_input] -filter:a "highpass=f=1000, lowpass=f=3000, acrusher=1:1:50:0:log" [filename_output]"})
+ if(SOUND_EFFECT_ROBOT)
+ output = world.shelleo({"[taskset] ffmpeg -y -hide_banner -loglevel error -i [filename_input] -filter:a "afftfilt=real='hypot(re,im)*sin(0)':imag='hypot(re,im)*cos(0)':win_size=1024:overlap=0.5, deesser=i=0.4, volume=volume=1.5" [filename_output]"})
+ if(SOUND_EFFECT_RADIO_ROBOT)
+ output = world.shelleo({"[taskset] ffmpeg -y -hide_banner -loglevel error -i [filename_input] -filter:a "afftfilt=real='hypot(re,im)*sin(0)':imag='hypot(re,im)*cos(0)':win_size=1024:overlap=0.5, deesser=i=0.4, volume=volume=1.5, highpass=f=1000, lowpass=f=3000, acrusher=1:1:50:0:log" [filename_output]"})
+ if(SOUND_EFFECT_MEGAPHONE)
+ output = world.shelleo({"[taskset] ffmpeg -y -hide_banner -loglevel error -i [filename_input] -filter:a "highpass=f=500, lowpass=f=4000, volume=volume=10, acrusher=1:1:45:0:log" [filename_output]"})
+ if(SOUND_EFFECT_MEGAPHONE_ROBOT)
+ output = world.shelleo({"[taskset] ffmpeg -y -hide_banner -loglevel error -i [filename_input] -filter:a "afftfilt=real='hypot(re,im)*sin(0)':imag='hypot(re,im)*cos(0)':win_size=1024:overlap=0.5, deesser=i=0.4, highpass=f=500, lowpass=f=4000, volume=volume=10, acrusher=1:1:45:0:log" [filename_output]"})
+ else
+ CRASH("Invalid sound effect chosen.")
+ var/errorlevel = output[SHELLEO_ERRORLEVEL]
+ var/stdout = output[SHELLEO_STDOUT]
+ var/stderr = output[SHELLEO_STDERR]
+ if(errorlevel)
+ error("Error: apply_sound_effect([effect], [filename_input], [filename_output]) - See debug logs.")
+ // TODO: SS220-TTS log_debug -> debug_world_log
+ debug_world_log("apply_sound_effect([effect], [filename_input], [filename_output]) STDOUT: [stdout]")
+ debug_world_log("apply_sound_effect([effect], [filename_input], [filename_output]) STDERR: [stderr]")
+ return FALSE
+ return TRUE
+
+//world/proc/shelleo
+#undef SHELLEO_ERRORLEVEL
+#undef SHELLEO_STDOUT
+#undef SHELLEO_STDERR
diff --git a/modular_ss220/modules/tts/code/tts_sound_TEMPORARY.dm b/modular_ss220/modules/tts/code/tts_sound_TEMPORARY.dm
new file mode 100644
index 000000000000000..a8bae493691ec14
--- /dev/null
+++ b/modular_ss220/modules/tts/code/tts_sound_TEMPORARY.dm
@@ -0,0 +1,77 @@
+// TODO: SS220-TTS Remove this file when upstream `/mob/proc/playsound_local` supports passing `wait` as parameter.
+// Copypasted `/mob/proc/playsound_local` method with `wait` support.
+/mob/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff_exponent = SOUND_FALLOFF_EXPONENT, channel = 0, pressure_affected = TRUE, sound/sound_to_use, max_distance, falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, distance_multiplier = 1, use_reverb = TRUE, wait = FALSE)
+ if(!wait)
+ return ..()
+
+ if(!client || !can_hear())
+ return
+
+ if(!sound_to_use)
+ sound_to_use = sound(get_sfx(soundin))
+
+ sound_to_use.wait = wait
+ sound_to_use.channel = channel || SSsounds.random_available_channel()
+ sound_to_use.volume = vol
+
+ if(vary)
+ if(frequency)
+ sound_to_use.frequency = frequency
+ else
+ sound_to_use.frequency = get_rand_frequency()
+
+ if(isturf(turf_source))
+ var/turf/turf_loc = get_turf(src)
+
+ //sound volume falloff with distance
+ var/distance = get_dist(turf_loc, turf_source) * distance_multiplier
+
+ if(max_distance) //If theres no max_distance we're not a 3D sound, so no falloff.
+ sound_to_use.volume -= (max(distance - falloff_distance, 0) ** (1 / falloff_exponent)) / ((max(max_distance, distance) - falloff_distance) ** (1 / falloff_exponent)) * sound_to_use.volume
+ //https://www.desmos.com/calculator/sqdfl8ipgf
+
+ if(pressure_affected)
+ //Atmosphere affects sound
+ var/pressure_factor = 1
+ var/datum/gas_mixture/hearer_env = turf_loc.return_air()
+ var/datum/gas_mixture/source_env = turf_source.return_air()
+
+ if(hearer_env && source_env)
+ var/pressure = min(hearer_env.return_pressure(), source_env.return_pressure())
+ if(pressure < ONE_ATMOSPHERE)
+ pressure_factor = max((pressure - SOUND_MINIMUM_PRESSURE)/(ONE_ATMOSPHERE - SOUND_MINIMUM_PRESSURE), 0)
+ else //space
+ pressure_factor = 0
+
+ if(distance <= 1)
+ pressure_factor = max(pressure_factor, 0.15) //touching the source of the sound
+
+ sound_to_use.volume *= pressure_factor
+ //End Atmosphere affecting sound
+
+ if(sound_to_use.volume <= 0)
+ return //No sound
+
+ var/dx = turf_source.x - turf_loc.x // Hearing from the right/left
+ sound_to_use.x = dx * distance_multiplier
+ var/dz = turf_source.y - turf_loc.y // Hearing from infront/behind
+ sound_to_use.z = dz * distance_multiplier
+ var/dy = (turf_source.z - turf_loc.z) * 5 * distance_multiplier // Hearing from above / below, multiplied by 5 because we assume height is further along coords.
+ sound_to_use.y = dy
+
+ sound_to_use.falloff = max_distance || 1 //use max_distance, else just use 1 as we are a direct sound so falloff isnt relevant.
+
+ // Sounds can't have their own environment. A sound's environment will be:
+ // 1. the mob's
+ // 2. the area's (defaults to SOUND_ENVRIONMENT_NONE)
+ if(sound_environment_override != SOUND_ENVIRONMENT_NONE)
+ sound_to_use.environment = sound_environment_override
+ else
+ var/area/A = get_area(src)
+ sound_to_use.environment = A.sound_environment
+
+ if(use_reverb && sound_to_use.environment != SOUND_ENVIRONMENT_NONE) //We have reverb, reset our echo setting
+ sound_to_use.echo[3] = -1300 //Room setting, 0 means normal reverb //SKYRAT EDIT CHANGE
+ sound_to_use.echo[4] = -1300 //RoomHF setting, 0 means normal reverb. //SKYRAT EDIT CHANGE
+
+ SEND_SOUND(src, sound_to_use)
diff --git a/modular_ss220/modules/tts/code/tts_subsystem.dm b/modular_ss220/modules/tts/code/tts_subsystem.dm
new file mode 100644
index 000000000000000..114f9c6d90b9cb3
--- /dev/null
+++ b/modular_ss220/modules/tts/code/tts_subsystem.dm
@@ -0,0 +1,576 @@
+SUBSYSTEM_DEF(tts)
+ name = "Text-to-Speech"
+ init_order = INIT_ORDER_DEFAULT
+ wait = 1 SECONDS
+ runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
+
+ var/tts_wanted = 0
+ var/tts_request_failed = 0
+ var/tts_request_succeeded = 0
+ var/tts_reused = 0
+ var/list/tts_errors = list()
+ var/tts_error_raw = ""
+
+ // Simple Moving Average RPS
+ var/list/tts_rps_list = list()
+ var/tts_sma_rps = 0
+
+ // Requests per Second (RPS), only real API requests
+ var/tts_rps = 0
+ var/tts_rps_counter = 0
+
+ // Total Requests per Second (TRPS), all TTS request, even reused
+ var/tts_trps = 0
+ var/tts_trps_counter = 0
+
+ // Reused Requests per Second (RRPS), only reused requests
+ var/tts_rrps = 0
+ var/tts_rrps_counter = 0
+
+ var/is_enabled = TRUE
+
+ var/list/datum/tts_seed/tts_seeds = list()
+ var/list/tts_seeds_names = list()
+ var/list/tts_seeds_names_by_donator_levels = list()
+ var/list/datum/tts_provider/tts_providers = list()
+
+ var/list/tts_local_channels_by_owner = list()
+
+ var/list/tts_requests_queue = list()
+ var/tts_requests_queue_limit = 100
+ var/tts_rps_limit = 5
+
+ var/list/tts_queue = list()
+ var/list/tts_effects_queue = list()
+
+ var/sanitized_messages_caching = TRUE
+ var/list/sanitized_messages_cache = list()
+ var/sanitized_messages_cache_hit = 0
+ var/sanitized_messages_cache_miss = 0
+
+ var/debug_mode_enabled = FALSE
+
+ var/static/list/tts_job_replacements = list(
+ "nanotrasen navy field officer" = "Полевой офицер флота Нанотрэйзен",
+ "nanotrasen navy officer" = "Офицер флота nanotrasen",
+ "supreme commander" = "Верховный главнокомандующий",
+ "solar federation general" = "Генерал Солнечной Федерации",
+ "special operations officer" = "Офицер специальных операций",
+ "civilian" = "Гражданский",
+ "tourist" = "Турист",
+ "businessman" = "Бизнэсмэн",
+ "trader" = "Торговец",
+ "assistant" = "Ассистент",
+ "chief engineer" = "Главный Инженер",
+ "station engineer" = "Станционный инженер",
+ "trainee engineer" = "Инженер-стажер",
+ "Engineer Assistant" = "Инженерный Ассистент",
+ "Technical Assistant" = "Технический Ассистент",
+ "Engineer Student" = "Инженер-практикант",
+ "Technical Student" = "Техник-практикант",
+ "Technical Trainee" = "Техник-стажер",
+ "maintenance technician" = "Техник по обслуживанию",
+ "engine technician" = "Техник по двигателям",
+ "electrician" = "Электрик",
+ "life support specialist" = "Специалист по жизнеобеспечению",
+ "atmospheric technician" = "Атмосферный техник",
+ "mechanic" = "Механик",
+ "chief medical officer" = "Главный врач",
+ "medical doctor" = "Врач",
+ "Intern" = "Интерн",
+ "Student Medical Doctor" = "Врач-практикант",
+ "Medical Assistant" = "Ассистирующий врач",
+ "surgeon" = "Хирург",
+ "nurse" = "Медсестра",
+ "coroner" = "К+оронэр",
+ "chemist" = "Химик",
+ "pharmacist" = "Фармацевт",
+ "pharmacologist" = "Фармаколог",
+ "geneticist" = "Генетик",
+ "virologist" = "Вирусолог",
+ "pathologist" = "Патологоанатом",
+ "microbiologist" = "Микробиолог",
+ "psychiatrist" = "Психиатр",
+ "psychologist" = "Психолог",
+ "therapist" = "Терапевт",
+ "paramedic" = "Парамедик",
+ "research director" = "Директор исследований",
+ "scientist" = "Учёный",
+ "student scientist" = "Учёный-практикант",
+ "Scientist Assistant" = "Научный Ассистент",
+ "Scientist Pregraduate" = "Учёный-бакалавр",
+ "Scientist Graduate" = "Научный выпускник",
+ "Scientist Postgraduate" = "Учёный-аспирант",
+ "anomalist" = "Аномалист",
+ "plasma researcher" = "Исследователь плазмы",
+ "xenobiologist" = "Ксенобиолог",
+ "chemical researcher" = "Химик-исследователь",
+ "roboticist" = "Робототехник",
+ "student robotist" = "Студент-робототехник",
+ "biomechanical engineer" = "Биомеханический инженер",
+ "mechatronic engineer" = "Инженер мехатроники",
+ "head of security" = "Глава службы безопасности",
+ "warden" = "Смотритель",
+ "detective" = "Детектив",
+ "forensic technician" = "Криминалист",
+ "security officer" = "Офицер службы безопасности",
+ "security cadet" = "Кадет службы безопасности",
+ "Security Assistant" = "Ассистент службы безопасности",
+ "Security Graduate" = "Выпускник кадетской академии",
+ "brig physician" = "Врач брига",
+ "security pod pilot" = "Пилот пода службы безопасности",
+ "ai" = "И И",
+ "cyborg" = "Киборг",
+ "robot" = "Робот",
+ "captain" = "Капитан",
+ "head of personnel" = "Глава персонала",
+ "nanotrasen representative" = "Представитель Нанотрэйзен",
+ "blueshield" = "Блюшилд",
+ "magistrate" = "Магистрат",
+ "internal affairs agent" = "Агент внутренних дел",
+ "human resources agent" = "Агент по персоналу",
+ "bartender" = "Бармэн",
+ "chef" = "Повар",
+ "cook" = "Кук",
+ "culinary artist" = "Кулинар",
+ "butcher" = "Мясник",
+ "botanist" = "Ботаник",
+ "hydroponicist" = "Гидропонист",
+ "botanical researcher" = "Ботаник-исследователь",
+ "quartermaster" = "Квартирмейстер",
+ "cargo technician" = "Карго техник",
+ "shaft miner" = "Шахтёр",
+ "spelunker" = "Спелеолог",
+ "clown" = "Клоун",
+ "mime" = "Мим",
+ "janitor" = "Уборщик",
+ "custodial technician" = "Техник по уходу за помещениями",
+ "librarian" = "Библиотекарь",
+ "journalist" = "Журналист",
+ "barber" = "Парикмахер",
+ "hair stylist" = "Стилист",
+ "beautician" = "Косметолог",
+ "explorer" = "Исследователь",
+ "chaplain" = "Священник",
+ "syndicate officer" = "Офицер синдиката",
+ "visitor" = "посетитель",
+ )
+
+/datum/controller/subsystem/tts/stat_entry(msg)
+ msg += "tRPS:[tts_trps] "
+ msg += "rRPS:[tts_rrps] "
+ msg += "RPS:[tts_rps] "
+ msg += "smaRPS:[tts_sma_rps] | "
+ msg += "W:[tts_wanted] "
+ msg += "F:[tts_request_failed] "
+ msg += "S:[tts_request_succeeded] "
+ msg += "R:[tts_reused] "
+ return ..()
+
+/datum/controller/subsystem/tts/PreInit()
+ . = ..()
+ for(var/path in subtypesof(/datum/tts_provider))
+ var/datum/tts_provider/provider = new path
+ tts_providers[provider.name] += provider
+ for(var/path in subtypesof(/datum/tts_seed))
+ var/datum/tts_seed/seed = new path
+ if(seed.value == "STUB")
+ continue
+ seed.provider = tts_providers[initial(seed.provider.name)]
+ tts_seeds[seed.name] = seed
+ tts_seeds_names += seed.name
+ tts_seeds_names_by_donator_levels["[seed.donator_level]"] += list(seed.name)
+ tts_seeds_names = sortTim(tts_seeds_names, /proc/cmp_text_asc)
+
+/datum/controller/subsystem/tts/Initialize(start_timeofday)
+ is_enabled = CONFIG_GET(flag/tts_enabled)
+ if(!is_enabled)
+ flags |= SS_NO_FIRE
+
+ return SS_INIT_SUCCESS
+
+/datum/controller/subsystem/tts/fire()
+ tts_rps = tts_rps_counter
+ tts_rps_counter = 0
+ tts_trps = tts_trps_counter
+ tts_trps_counter = 0
+ tts_rrps = tts_rrps_counter
+ tts_rrps_counter = 0
+
+ tts_rps_list += tts_rps
+ if(tts_rps_list.len > 15)
+ tts_rps_list.Cut(1,2)
+
+ var/rps_sum = 0
+ for(var/rps in tts_rps_list)
+ rps_sum += rps
+ tts_sma_rps = round(rps_sum / tts_rps_list.len, 0.1)
+
+ var/free_rps = clamp(tts_rps_limit - tts_rps, 0, tts_rps_limit)
+ var/requests = tts_requests_queue.Copy(1, clamp(LAZYLEN(tts_requests_queue), 0, free_rps) + 1)
+ for(var/request in requests)
+ var/text = request[1]
+ var/datum/tts_seed/seed = request[2]
+ var/datum/callback/proc_callback = request[3]
+ var/datum/tts_provider/provider = seed.provider
+ provider.request(text, seed, proc_callback)
+ tts_rps_counter++
+ tts_requests_queue.Cut(1, clamp(LAZYLEN(tts_requests_queue), 0, free_rps) + 1)
+
+ if(sanitized_messages_caching)
+ sanitized_messages_cache.Cut()
+ if(debug_mode_enabled)
+ world.log << "sanitized_messages_cache: HIT=[sanitized_messages_cache_hit] / MISS=[sanitized_messages_cache_miss]"
+ sanitized_messages_cache_hit = 0
+ sanitized_messages_cache_miss = 0
+
+/datum/controller/subsystem/tts/Recover()
+ is_enabled = SStts.is_enabled
+ tts_wanted = SStts.tts_wanted
+ tts_request_failed = SStts.tts_request_failed
+ tts_request_succeeded = SStts.tts_request_succeeded
+ tts_reused = SStts.tts_reused
+
+/datum/controller/subsystem/tts/proc/queue_request(text, datum/tts_seed/seed, datum/callback/proc_callback)
+ if(LAZYLEN(tts_requests_queue) > tts_requests_queue_limit)
+ is_enabled = FALSE
+ to_chat(world, span_announce("SERVER: очередь запросов превысила лимит, подсистема SStts принудительно отключена!"))
+ return FALSE
+
+ if(tts_rps_counter < tts_rps_limit)
+ var/datum/tts_provider/provider = seed.provider
+ provider.request(text, seed, proc_callback)
+ tts_rps_counter++
+ return TRUE
+
+ tts_requests_queue += list(list(text, seed, proc_callback))
+ return TRUE
+
+/datum/controller/subsystem/tts/proc/get_tts(atom/speaker, mob/listener, message, seed_name, is_local = TRUE, effect = SOUND_EFFECT_NONE, traits = TTS_TRAIT_RATE_FASTER, preSFX = null, postSFX = null)
+ if(!is_enabled)
+ return
+ if(!message)
+ return
+ if(isnull(listener) || !listener.client)
+ return
+ if(isnull(seed_name) || !(seed_name in tts_seeds))
+ return
+ var/datum/tts_seed/seed = tts_seeds[seed_name]
+
+ tts_wanted++
+ tts_trps_counter++
+
+ var/datum/tts_provider/provider = seed.provider
+ if(!provider.is_enabled)
+ return
+ if(provider.throttle_check())
+ return
+
+ var/dirty_text = message
+ var/text = sanitize_tts_input(dirty_text)
+
+ if(!text || length_char(text) > MAX_MESSAGE_LEN)
+ return
+
+ if(traits & TTS_TRAIT_RATE_FASTER)
+ text = provider.rate_faster(text)
+
+ if(traits & TTS_TRAIT_RATE_MEDIUM)
+ text = provider.rate_medium(text)
+
+ if(traits & TTS_TRAIT_PITCH_WHISPER)
+ text = provider.pitch_whisper(text)
+
+ var/hash = rustg_hash_string(RUSTG_HASH_MD5, text)
+ var/filename = "sound/tts_cache/[seed.name]/[hash]"
+
+ var/datum/callback/play_tts_cb = CALLBACK(src, PROC_REF(play_tts), speaker, listener, filename, is_local, effect, preSFX, postSFX)
+
+ if(fexists("[filename].ogg"))
+ tts_reused++
+ tts_rrps_counter++
+ play_tts(speaker, listener, filename, is_local, effect, preSFX, postSFX)
+ return
+
+ if(LAZYLEN(tts_queue[filename]))
+ tts_reused++
+ tts_rrps_counter++
+ LAZYADD(tts_queue[filename], play_tts_cb)
+ return
+
+ var/datum/callback/cb = CALLBACK(src, PROC_REF(get_tts_callback), speaker, listener, filename, seed, is_local, effect, preSFX, postSFX)
+ queue_request(text, seed, cb)
+ LAZYADD(tts_queue[filename], play_tts_cb)
+
+/datum/controller/subsystem/tts/proc/get_tts_callback(atom/speaker, mob/listener, filename, datum/tts_seed/seed, is_local, effect, preSFX, postSFX, datum/http_response/response)
+ var/datum/tts_provider/provider = seed.provider
+
+ // Bail if it errored
+ if(response.errored)
+ provider.failed_requests++
+ if(provider.failed_requests >= provider.failed_requests_limit)
+ provider.is_enabled = FALSE
+ message_admins("Error connecting to [provider.name] TTS API. Please inform a maintainer or server host. ")
+ return
+
+ if(response.status_code != 200)
+ provider.failed_requests++
+ if(provider.failed_requests >= provider.failed_requests_limit)
+ provider.is_enabled = FALSE
+ message_admins("Error performing [provider.name] TTS API request (Code: [response.status_code]) ")
+ tts_request_failed++
+ if(response.status_code)
+ if(tts_errors["[response.status_code]"])
+ tts_errors["[response.status_code]"]++
+ else
+ tts_errors += "[response.status_code]"
+ tts_errors["[response.status_code]"] = 1
+ tts_error_raw = response.error
+ return
+
+ tts_request_succeeded++
+
+ var/voice = provider.process_response(response)
+ if(!voice)
+ return
+
+ rustg_file_write_b64decode(voice, "[filename].ogg")
+
+ if (!CONFIG_GET(flag/tts_cache))
+ addtimer(CALLBACK(src, PROC_REF(cleanup_tts_file), "[filename].ogg"), 30 SECONDS)
+
+ for(var/datum/callback/cb in tts_queue[filename])
+ cb.InvokeAsync()
+ tts_queue[filename] -= cb
+
+ tts_queue -= filename
+
+/datum/controller/subsystem/tts/proc/play_tts(atom/speaker, mob/listener, filename, is_local = TRUE, effect = SOUND_EFFECT_NONE, preSFX = null, postSFX = null)
+ if(isnull(listener) || !listener.client)
+ return
+
+ var/voice
+ switch(effect)
+ if(SOUND_EFFECT_NONE)
+ voice = "[filename].ogg"
+ if(SOUND_EFFECT_RADIO)
+ voice = "[filename]_radio.ogg"
+ if(SOUND_EFFECT_ROBOT)
+ voice = "[filename]_robot.ogg"
+ if(SOUND_EFFECT_RADIO_ROBOT)
+ voice = "[filename]_radio_robot.ogg"
+ if(SOUND_EFFECT_MEGAPHONE)
+ voice = "[filename]_megaphone.ogg"
+ if(SOUND_EFFECT_MEGAPHONE_ROBOT)
+ voice = "[filename]_megaphone_robot.ogg"
+ else
+ CRASH("Invalid sound effect chosen.")
+ if(effect != SOUND_EFFECT_NONE)
+ if(!fexists(voice))
+ var/datum/callback/play_tts_cb = CALLBACK(src, PROC_REF(play_tts), speaker, listener, filename, is_local, effect, preSFX, postSFX)
+ if(LAZYLEN(tts_effects_queue[voice]))
+ LAZYADD(tts_effects_queue[voice], play_tts_cb)
+ return
+ LAZYADD(tts_effects_queue[voice], play_tts_cb)
+ apply_sound_effect(effect, "[filename].ogg", voice)
+ for(var/datum/callback/cb in tts_effects_queue[voice])
+ tts_effects_queue[voice] -= cb
+ if(cb == play_tts_cb)
+ continue
+ cb.InvokeAsync()
+ tts_effects_queue -= voice
+
+ var/turf/turf_source = get_turf(speaker)
+
+ var/volume
+ var/channel
+ if(is_local)
+ volume = LOCAL_TTS_VOLUME(listener)
+ channel = get_local_channel_by_owner(speaker)
+ else
+ volume = RADIO_TTS_VOLUME(listener)
+ channel = CHANNEL_TTS_RADIO
+
+ var/sound/output = sound(voice)
+ output.status = SOUND_STREAM
+
+ if(isnull(speaker))
+ output.wait = TRUE
+ output.channel = channel
+ // TODO: SS220-TTS
+ // output.volume = volume * listener.client.prefs.get_channel_volume(CHANNEL_GENERAL) * listener.client.prefs.get_channel_volume(channel)
+ output.volume = volume
+ output.environment = -1
+
+ if(output.volume <= 0)
+ return
+
+ if(preSFX)
+ play_sfx(listener, preSFX, output.channel, output.volume, output.environment)
+
+ SEND_SOUND(listener, output)
+ return
+
+ if(preSFX)
+ play_sfx(listener, preSFX, output.channel, output.volume, output.environment)
+
+ listener.playsound_local(turf_source, output, volume, sound_to_use = output, channel = channel, wait = TRUE)
+
+ if(!output || output.volume <= 0)
+ return
+
+ if(postSFX)
+ play_sfx(listener, postSFX, output.channel, output.volume, output.environment)
+
+/datum/controller/subsystem/tts/proc/play_sfx(mob/listener, sfx, channel, volume, environment)
+ var/sound/output = sound(sfx)
+ output.status = SOUND_STREAM
+ output.wait = TRUE
+ output.channel = channel
+ output.volume = volume
+ output.environment = environment
+ SEND_SOUND(listener, output)
+
+/datum/controller/subsystem/tts/proc/get_local_channel_by_owner(owner)
+ var/channel = tts_local_channels_by_owner[owner]
+ if(isnull(channel))
+ channel = SSsounds.reserve_sound_channel_datumless()
+ tts_local_channels_by_owner[owner] = channel
+ return channel
+
+/datum/controller/subsystem/tts/proc/cleanup_tts_file(filename)
+ fdel(filename)
+
+/datum/controller/subsystem/tts/proc/get_available_seeds(owner)
+ var/list/_tts_seeds_names = list()
+ _tts_seeds_names |= tts_seeds_names
+
+ if(!ismob(owner))
+ return _tts_seeds_names
+
+ var/mob/M = owner
+
+ if(!M.client)
+ return _tts_seeds_names
+
+ // TODO: SS220-TTS
+ // for(var/donator_level in 0 to DONATOR_LEVEL_MAX)
+ // if(M.client.donator_level < donator_level)
+ // _tts_seeds_names -= tts_seeds_names_by_donator_levels["[donator_level]"]
+ return _tts_seeds_names
+
+/datum/controller/subsystem/tts/proc/get_random_seed(owner)
+ return pick(get_available_seeds(owner))
+
+/datum/controller/subsystem/tts/proc/sanitize_tts_input(message)
+ var/hash
+ if(sanitized_messages_caching)
+ hash = rustg_hash_string(RUSTG_HASH_MD5, message)
+ if(sanitized_messages_cache[hash])
+ sanitized_messages_cache_hit++
+ return sanitized_messages_cache[hash]
+ sanitized_messages_cache_miss++
+ . = message
+ . = trim(.)
+
+ var/static/regex/punctuation_check = new(@"[.,?!]\Z")
+ if(!punctuation_check.Find(.))
+ . += "."
+
+ var/static/regex/html_tags = new(@"<[^>]*>", "g")
+ . = html_tags.Replace(., "")
+ . = html_decode(.)
+
+ var/static/regex/forbidden_symbols = new(@"[^a-zA-Z0-9а-яА-ЯёЁ,!?+./ \r\n\t:—()-]", "g")
+ . = forbidden_symbols.Replace(., "")
+
+ var/static/regex/words = new(@"(? {
case Page.Quirks:
pageContents = ;
break;
+ case Page.Voice:
+ pageContents = ;
+ break;
default:
exhaustiveCheck(currentPage);
}
@@ -193,6 +199,17 @@ export const CharacterPreferenceWindow = (props) => {
Quirks
+
+ {Boolean(data.tts_enabled) && (
+
+
+ Voice
+
+
+ )}
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/VoicePage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/VoicePage.tsx
new file mode 100644
index 000000000000000..29b86e4bd6a6f6f
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/VoicePage.tsx
@@ -0,0 +1,275 @@
+import { useBackend, useLocalState } from '../../backend';
+import { Button, LabeledList, Table, Section, Dropdown, Input, BlockQuote, Box, Icon } from '../../components';
+import { PreferencesMenuData } from './data';
+
+const donatorTiers = {
+ 0: 'Бесплатные',
+ 1: 'Tier I',
+ 2: 'Tier II',
+ 3: 'Tier III',
+ 4: 'Tier IV',
+};
+
+const gendersIcons = {
+ 'Мужской': {
+ icon: 'mars',
+ color: 'blue',
+ },
+ 'Женский': {
+ icon: 'venus',
+ color: 'purple',
+ },
+ 'Любой': {
+ icon: 'venus-mars',
+ color: 'white',
+ },
+};
+
+const getCheckboxGroup = (
+ itemsList,
+ selectedList,
+ setSelected,
+ contentKey: string | null = null
+) => {
+ return itemsList.map((item) => {
+ const title = (contentKey && item[contentKey]) ?? item;
+ return (
+ {
+ if (selectedList.includes(item)) {
+ setSelected(
+ selectedList.filter(
+ (i) => ((contentKey && i[contentKey]) ?? i) !== item
+ )
+ );
+ } else {
+ setSelected([item, ...selectedList]);
+ }
+ }}
+ />
+ );
+ });
+};
+
+export const VoicePage = (props, context) => {
+ const { act, data } = useBackend(context);
+
+ const {
+ providers,
+ seeds,
+ phrases,
+ character_preferences: {
+ misc: { tts_seed },
+ },
+ } = data;
+
+ const donator_level = 5;
+
+ const categories = seeds
+ .map((seed) => seed.category)
+ .filter((category, i, a) => a.indexOf(category) === i);
+ const genders = seeds
+ .map((seed) => seed.gender)
+ .filter((gender, i, a) => a.indexOf(gender) === i);
+ const donatorLevels = seeds
+ .map((seed) => seed.donator_level)
+ .filter((level, i, a) => a.indexOf(level) === i)
+ .map((level) => donatorTiers[level]);
+
+ const [selectedProviders, setSelectedProviders] = useLocalState(
+ context,
+ 'selectedProviders',
+ providers
+ );
+ const [selectedGenders, setSelectedGenders] = useLocalState(
+ context,
+ 'selectedGenders',
+ genders
+ );
+ const [selectedCategories, setSelectedCategories] = useLocalState(
+ context,
+ 'selectedCategories',
+ categories
+ );
+ const [selectedDonatorLevels, setSelectedDonatorLevels] = useLocalState(
+ context,
+ 'selectedDonatorLevels',
+ donatorLevels
+ );
+ const [selectedPhrase, setSelectedPhrase] = useLocalState(
+ context,
+ 'selectedPhrase',
+ phrases[0]
+ );
+ const [searchtext, setSearchtext] = useLocalState(context, 'searchtext', '');
+
+ let providerCheckboxes = getCheckboxGroup(
+ providers,
+ selectedProviders,
+ setSelectedProviders,
+ 'name'
+ );
+ let genderesCheckboxes = getCheckboxGroup(
+ genders,
+ selectedGenders,
+ setSelectedGenders
+ );
+ let categoriesCheckboxes = getCheckboxGroup(
+ categories,
+ selectedCategories,
+ setSelectedCategories
+ );
+ let donatorLevelsCheckboxes = getCheckboxGroup(
+ donatorLevels,
+ selectedDonatorLevels,
+ setSelectedDonatorLevels
+ );
+
+ let phrasesSelect = (
+ setSelectedPhrase(value)}
+ />
+ );
+
+ let searchBar = (
+ setSearchtext(value)}
+ />
+ );
+
+ const availableSeeds = seeds
+ .sort((a, b) => {
+ const aname = a.name.toLowerCase();
+ const bname = b.name.toLowerCase();
+ if (aname > bname) {
+ return 1;
+ }
+ if (aname < bname) {
+ return -1;
+ }
+ return 0;
+ })
+ .filter(
+ (seed) =>
+ selectedProviders.some((provider) => provider.name === seed.provider) &&
+ selectedGenders.includes(seed.gender) &&
+ selectedCategories.includes(seed.category) &&
+ selectedDonatorLevels.includes(donatorTiers[seed.donator_level]) &&
+ seed.name.toLowerCase().includes(searchtext.toLowerCase())
+ );
+
+ let seedsRow = availableSeeds.map((seed) => {
+ return (
+
+
+ act('select_voice', { seed: seed.name })}
+ />
+
+
+
+ act('listen', { seed: seed.name, phrase: selectedPhrase })
+ }
+ />
+
+ 0 && tts_seed !== seed.name
+ ? 'orange'
+ : 'white'
+ }>
+ {seed.name}
+
+
+ {seed.category}
+
+
+
+
+
+ {seed.donator_level > 0 && (
+ <>
+ {donatorTiers[seed.donator_level]}
+
+ >
+ )}
+
+
+ );
+ });
+
+ return (
+ <>
+
+
+
+ {providerCheckboxes}
+
+ {genderesCheckboxes}
+
+ {categoriesCheckboxes}
+
+
+ {donatorLevelsCheckboxes}
+
+ {phrasesSelect}
+ {searchBar}
+
+
+
+
+
+
+ {`Для поддержания и развития сообщества в условиях растущих расходов часть голосов пришлось сделать доступными только за материальную поддержку сообщества.`}
+
+
+ {`Подробнее об этом можно узнать в нашем Discord-сообществе.`}
+
+
+
+ >
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts
index f92168a465a58cc..e229bac207341b5 100644
--- a/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts
@@ -199,6 +199,7 @@ export type PreferencesMenuData = {
gender: Gender;
joblessrole: JoblessRole;
species: string;
+ tts_seed: string;
};
randomization: Record;
@@ -244,6 +245,21 @@ export type PreferencesMenuData = {
active_slot: number;
name_to_use: string;
+ tts_enabled: BooleanLike;
+ providers: Array<{
+ name: string;
+ is_enabled: BooleanLike;
+ }>;
+ seeds: Array<{
+ name: string;
+ value: string;
+ category: string;
+ gender: string;
+ provider: string;
+ donator_level: number;
+ }>;
+ phrases: string[];
+
window: Window;
};
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ss220/tts.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ss220/tts.tsx
new file mode 100644
index 000000000000000..2b20a3e8847b538
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/ss220/tts.tsx
@@ -0,0 +1,37 @@
+import { Feature, FeatureValueProps, FeatureNumericData } from '../../base';
+import { Box, Slider } from '../../../../../../components';
+
+const SLIDER_STEP_SIZE_FOR_SETTINGS_WINDOW_WIDTH = 4.1;
+
+const FeatureSlider = (
+ props: FeatureValueProps
+) => {
+ if (!props.serverData) {
+ return Loading... ;
+ }
+
+ return (
+ {
+ props.handleSetValue(value);
+ }}
+ minValue={props.serverData.minimum}
+ maxValue={props.serverData.maximum}
+ step={props.serverData.step}
+ value={props.value}
+ />
+ );
+};
+
+export const sound_tts_local: Feature = {
+ name: 'Local TTS volume (0 to disable)',
+ category: 'SOUND',
+ component: FeatureSlider,
+};
+
+export const sound_tts_radio: Feature = {
+ name: 'Radio TTS volume (0 to disable)',
+ category: 'SOUND',
+ component: FeatureSlider,
+};