diff --git a/config/bandastation/bandastation_config.txt b/config/bandastation/bandastation_config.txt
index bb67611772896..eeb290cb866c2 100644
--- a/config/bandastation/bandastation_config.txt
+++ b/config/bandastation/bandastation_config.txt
@@ -1,4 +1,5 @@
## Text-to-speech
#TTS_TOKEN_SILERO mytoken
#TTS_ENABLED
-#TTS_CACHE
+#TTS_CACHE_ENABLED
+#TTS_API_URL_SILERO
diff --git a/config/bandastation/tts_replacements.json b/config/bandastation/tts_replacements.json
new file mode 100644
index 0000000000000..d62e9b1a7be9d
--- /dev/null
+++ b/config/bandastation/tts_replacements.json
@@ -0,0 +1,180 @@
+{
+ "tts_acronym_replacements": {
+ "нт": "Эн Тэ",
+ "смо": "Эс Мэ О",
+ "гп": "Гэ Пэ",
+ "рд": "Эр Дэ",
+ "гсб": "Гэ Эс Бэ",
+ "срп": "Эс Эр Пэ",
+ "цк": "Цэ Каа",
+ "рнд": "Эр Эн Дэ",
+ "сб": "Эс Бэ",
+ "рцд": "Эр Цэ Дэ",
+ "брпд": "Бэ Эр Пэ Дэ",
+ "рпд": "Эр Пэ Дэ",
+ "рпед": "Эр Пед",
+ "тсф": "Тэ Эс Эф",
+ "срт": "Эс Эр Тэ",
+ "обр": "О Бэ Эр",
+ "кпк": "Кэ Пэ Каа",
+ "пда": "Пэ Дэ А",
+ "id": "Ай Ди",
+ "мщ": "Эм Ще",
+ "вт": "Вэ Тэ",
+ "ерп": "Йе Эр Пэ",
+ "се": "Эс Йе",
+ "апц": "А Пэ Цэ",
+ "лкп": "Эл Ка Пэ",
+ "см": "Эс Эм",
+ "ека": "Йе Ка",
+ "ка": "Кэ А",
+ "бса": "Бэ Эс Аа",
+ "днк": "Дэ Эн Ка",
+ "тк": "Тэ Ка",
+ "бфл": "Бэ Эф Эл",
+ "бщ": "Бэ Щэ",
+ "кк": "Кэ Ка",
+ "ск": "Эс Ка",
+ "зк": "Зэ Ка",
+ "ерт": "Йе Эр Тэ",
+ "вкд": "Вэ Ка Дэ",
+ "нтр": "Эн Тэ Эр",
+ "пнт": "Пэ Эн Тэ",
+ "авд": "А Вэ Дэ",
+ "пнв": "Пэ Эн Вэ",
+ "ссд": "Эс Эс Дэ",
+ "кпб": "Кэ Пэ Бэ",
+ "сссп": "Эс Эс Эс Пэ",
+ "крб": "Ка Эр Бэ",
+ "бд": "Бэ Дэ",
+ "сст": "Эс Эс Тэ",
+ "скс": "Эс Ка Эс",
+ "икн": "И Ка Эн",
+ "нсс": "Эн Эс Эс",
+ "емп": "Йе Эм Пэ",
+ "бс": "Бэ Эс",
+ "цкс": "Цэ Ка Эс",
+ "срд": "Эс Эр Дэ",
+ "жпс": "Джи Пи Эс",
+ "gps": "Джи Пи Эс",
+ "ннксс": "Эн Эн Ка Эс Эс",
+ "ss": "Эс Эс",
+ "сс": "Эс Эс",
+ "тесла": "тэсла",
+ "трейзен": "трэйзэн",
+ "нанотрейзен": "нанотрэйзэн",
+ "мед": "м ед",
+ "меде": "м еде",
+ "кз": "Кэ Зэ",
+ "гбс": "Гэ Бэ Эс",
+ "цпсс": "Цэ Пэ Эс Эс",
+ "гкк": "Гэ Кэ Ка"
+ },
+ "tts_job_replacements": {
+ "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": "Криминалист",
+ "junior security officer": "Младший офицер службы безопасности",
+ "security officer": "Офицер службы безопасности",
+ "security trainer": "Тренер службы безопасности",
+ "security cadet": "Кадет службы безопасности",
+ "Security Assistant": "Ассистент службы безопасности",
+ "Security Graduate": "Выпускник кадетской академии",
+ "brig physician": "Врач брига",
+ "security pod pilot": "Пилот пода службы безопасности",
+ "captain": "Капитан",
+ "ai": "И И",
+ "cyborg": "Киборг",
+ "robot": "Робот",
+ "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": "посетитель"
+ }
+}
diff --git a/dependencies.sh b/dependencies.sh
index 087c337a0461f..fcb48eefcc31b 100644
--- a/dependencies.sh
+++ b/dependencies.sh
@@ -9,6 +9,7 @@ export BYOND_MINOR=1633
#rust_g git tag
export RUST_G_VERSION=3.1.0
+export RUST_G_VERSION_SS220=3.0.0-ss220
#node version
export NODE_VERSION=20
diff --git a/modular_bandastation/_defines220/_defines220.dme b/modular_bandastation/_defines220/_defines220.dme
index 2e4cf7f6c8a23..8bc961b39df80 100644
--- a/modular_bandastation/_defines220/_defines220.dme
+++ b/modular_bandastation/_defines220/_defines220.dme
@@ -1,7 +1,10 @@
#include "_defines220.dm"
+#include "code/signals_atom.dm"
#include "code/defines/keybindings.dm"
+#include "code/defines/misc.dm"
#include "code/defines/spans.dm"
+#include "code/defines/text_to_speech.dm"
#include "code/signals_mob/signals_mob_ai.dm"
#include "code/signals_mob/signals_mob_carbon.dm"
#include "code/signals_mob/signals_mob_living.dm"
diff --git a/modular_bandastation/_defines220/code/defines/misc.dm b/modular_bandastation/_defines220/code/defines/misc.dm
new file mode 100644
index 0000000000000..84efa510030c4
--- /dev/null
+++ b/modular_bandastation/_defines220/code/defines/misc.dm
@@ -0,0 +1,6 @@
+///Do (almost) nothing - indev placeholder for switch case implementations etc
+#define NOOP (.=.)
+/// Copies the L from element START to elememt END if L is initialized, otherwise returns an empty list.
+#define LAZYCOPY_RANGE(L, START, END) ( L ? L.Copy(START, END) : list() )
+/// Cuts the L from element START to elememt END if L is initialized, otherwise returns an empty list.
+#define LAZYCUT(L, START, END) ( L ? L.Cut(START, END) : NOOP )
diff --git a/modular_bandastation/tts/code/_tts_defines.dm b/modular_bandastation/_defines220/code/defines/text_to_speech.dm
similarity index 64%
rename from modular_bandastation/tts/code/_tts_defines.dm
rename to modular_bandastation/_defines220/code/defines/text_to_speech.dm
index 9d358f17ae50d..8d56e1734a006 100644
--- a/modular_bandastation/tts/code/_tts_defines.dm
+++ b/modular_bandastation/_defines220/code/defines/text_to_speech.dm
@@ -1,18 +1,11 @@
#define VV_HK_SELECT_TTS_VOICE "select_tts_voice"
-#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 1008
-
#define TTS_TRAIT_PITCH_WHISPER (1<<1)
#define TTS_TRAIT_RATE_FASTER (1<<2)
#define TTS_TRAIT_RATE_MEDIUM (1<<3)
+#define TTS_TRAIT_ROBOTIZE "tts_trait_robotize"
+
#define TTS_CATEGORY_OTHER "Другое"
#define TTS_CATEGORY_WARCRAFT3 "WarCraft 3"
#define TTS_CATEGORY_HALFLIFE2 "Half-Life 2"
@@ -34,6 +27,25 @@
#define TTS_CATEGORY_HEARTHSTONE "Hearthstone"
#define TTS_CATEGORY_VALORANT "Valorant"
#define TTS_CATEGORY_EVILISLANDS "Evil Islands"
+#define TTS_CATEGORY_WITCHER "Witcher"
+#define TTS_CATEGORY_LEFT4DEAD "Left 4 Dead"
+#define TTS_CATEGORY_SPONGEBOB "SpongeBob"
+#define TTS_CATEGORY_TINYBUNNY "Tiny Bunny"
+#define TTS_CATEGORY_BALDURS_GATE_3 "Baldur's gate 3"
+#define TTS_CATEGORY_PORTAL "Portal"
+#define TTS_CATEGORY_TMNT "Teenage mutant ninja turtle"
+#define TTS_CATEGORY_STAR_WARS "Star Wars"
+#define TTS_CATEGORY_TRANSFORMERS "Transformers"
+#define TTS_CATEGORY_LOTR "The Lord of the rings"
+#define TTS_CATEGORY_SHREK "Shrek"
+#define TTS_CATEGORY_POTC "Pirates of the Caribbean"
+#define TTS_CATEGORY_HARRY_POTTER "Harry Potter"
+#define TTS_CATEGORY_X3 "X3"
+#define TTS_CATEGORY_OVERLORD2 "The Overlord 2"
+#define TTS_CATEGORY_MARVEL "Marvel"
+#define TTS_CATEGORY_WOW "World of Warcraft"
+#define TTS_CATEGORY_TREASURE_ISLAND "Treasure Island"
+#define TTS_CATEGORY_BOYS_WORD "Слово пацана"
#define TTS_GENDER_ANY "Любой"
#define TTS_GENDER_MALE "Мужской"
@@ -55,10 +67,9 @@
"Капитан, вы уверены что хотите назначить клоуна на должность главы персонала?",\
)
-#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)
+#define BIG_WORKER_TIER 220
+#define LITTLE_WORKER_TIER 110
-/proc/error(msg)
- log_world("## ERROR: [msg]")
+#define BIG_WORKER_TTS_LEVEL 3
+#define LITTLE_WORKER_TTS_LEVEL 1
+#define DONATOR_LEVEL_MAX 5
diff --git a/modular_bandastation/_defines220/code/signals_atom.dm b/modular_bandastation/_defines220/code/signals_atom.dm
new file mode 100644
index 0000000000000..6cb23c4e1f485
--- /dev/null
+++ b/modular_bandastation/_defines220/code/signals_atom.dm
@@ -0,0 +1,8 @@
+///from base of atom/change_tts_seed(): (mob/chooser, override, new_traits)
+#define COMSIG_ATOM_TTS_SEED_CHANGE "atom_tts_seed_change"
+///from base of atom/cast_tts: (mob/listener, message, atom/location, is_local, effect, traits, preSFX, postSFX)
+#define COMSIG_ATOM_TTS_CAST "atom_tts_cast"
+///from base of atom/tts_trait_add(): (trait)
+#define COMSIG_ATOM_TTS_TRAIT_ADD "atom_tts_trait_add"
+///from base of atom/tts_trait_remove(): (trait)
+#define COMSIG_ATOM_TTS_TRAIT_REMOVE "atom_tts_trait_remove"
diff --git a/modular_bandastation/_helpers220/code/unsorted.dm b/modular_bandastation/_helpers220/code/unsorted.dm
index efb9c8a55e788..e69de29bb2d1d 100644
--- a/modular_bandastation/_helpers220/code/unsorted.dm
+++ b/modular_bandastation/_helpers220/code/unsorted.dm
@@ -1,32 +0,0 @@
-/** Get all hearers in range, ignores walls and such. Code stolen from `/proc/get_hearers_in_view()`
- * Much faster and less expensive than range()
-*/
-/proc/get_hearers_in_range(range_radius, atom/source)
- var/turf/center_turf = get_turf(source)
- if(!center_turf)
- return
-
- . = list()
- var/old_luminosity = center_turf.luminosity
- if(range_radius <= 0) //special case for if only source cares
- for(var/atom/movable/target as anything in center_turf)
- var/list/recursive_contents = target.important_recursive_contents?[RECURSIVE_CONTENTS_HEARING_SENSITIVE]
- if(recursive_contents)
- . += recursive_contents
- return .
-
- var/list/hearables_from_grid = SSspatial_grid.orthogonal_range_search(source, RECURSIVE_CONTENTS_HEARING_SENSITIVE, range_radius)
-
- if(!length(hearables_from_grid))//we know that something is returned by the grid, but we dont know if we need to actually filter down the output
- return .
-
- var/list/assigned_oranges_ears = SSspatial_grid.assign_oranges_ears(hearables_from_grid)
-
- for(var/mob/oranges_ear/ear in range(range_radius, center_turf))
- . += ear.references
-
- for(var/mob/oranges_ear/remaining_ear as anything in assigned_oranges_ears) //we need to clean up our mess
- remaining_ear.unassign()
-
- center_turf.luminosity = old_luminosity
- return .
diff --git a/modular_bandastation/_modpacks.dm b/modular_bandastation/_modpacks.dm
index 347fcd019b6b9..68a24b2f48e0a 100644
--- a/modular_bandastation/_modpacks.dm
+++ b/modular_bandastation/_modpacks.dm
@@ -30,6 +30,8 @@ SUBSYSTEM_DEF(modpacks)
var/fail_msg = package.post_initialize()
if(fail_msg)
CRASH("Modpack [(istype(package) && package.name) || "Unknown"] failed to post-initialize: [fail_msg]")
+
+ return SS_INIT_SUCCESS
/client/verb/modpacks_list()
set name = "Modpacks List"
diff --git a/modular_bandastation/_singletons/_singletons.dm b/modular_bandastation/_singletons/_singletons.dm
new file mode 100644
index 0000000000000..d8b23d11f1a63
--- /dev/null
+++ b/modular_bandastation/_singletons/_singletons.dm
@@ -0,0 +1,4 @@
+/datum/modpack/singletons
+ name = "Singletons"
+ desc = "Ports Singletons from Sierra"
+ author = "larentoun"
diff --git a/modular_bandastation/_singletons/_singletons.dme b/modular_bandastation/_singletons/_singletons.dme
new file mode 100644
index 0000000000000..324fefed37667
--- /dev/null
+++ b/modular_bandastation/_singletons/_singletons.dme
@@ -0,0 +1,5 @@
+#include "_singletons.dm"
+
+#include "code/_defines.dm"
+#include "code/repository.dm"
+#include "code/singletons.dm"
diff --git a/modular_bandastation/_singletons/code/_defines.dm b/modular_bandastation/_singletons/code/_defines.dm
new file mode 100644
index 0000000000000..fd4cc7e73d1d0
--- /dev/null
+++ b/modular_bandastation/_singletons/code/_defines.dm
@@ -0,0 +1,23 @@
+/*
+* Performance behaviors for avoiding calling procs unecessarily on the Singletons global.
+*/
+
+/// Get a singleton instance according to path P. Creates it if necessary. Null if abstract or not a singleton.
+#define GET_SINGLETON(P)\
+ (ispath(P, /datum/singleton) ? (GLOB.Singletons.resolved_instances[P] ? GLOB.Singletons.instances[P] : GLOB.Singletons.GetInstance(P)) : null)
+
+/// Get a (path = instance) map of valid singletons according to typesof(P).
+#define GET_SINGLETON_TYPE_MAP(P)\
+ (ispath(P, /datum/singleton) ? (GLOB.Singletons.resolved_type_maps[P] ? GLOB.Singletons.type_maps[P] : GLOB.Singletons.GetTypeMap(P)) : list())
+
+/// Get a (path = instance) map of valid singletons according to subtypesof(P).
+#define GET_SINGLETON_SUBTYPE_MAP(P)\
+ (ispath(P, /datum/singleton) ? (GLOB.Singletons.resolved_subtype_maps[P] ? GLOB.Singletons.subtype_maps[P] : GLOB.Singletons.GetSubtypeMap(P)) : list())
+
+/// Get a list of valid singletons according to typesof(path).
+#define GET_SINGLETON_TYPE_LIST(P)\
+ (ispath(P, /datum/singleton) ? (GLOB.Singletons.resolved_type_lists[P] ? GLOB.Singletons.type_lists[P] : GLOB.Singletons.GetTypeList(P)) : list())
+
+/// Get a list of valid singletons according to subtypesof(path).
+#define GET_SINGLETON_SUBTYPE_LIST(P)\
+ (ispath(P, /datum/singleton) ? (GLOB.Singletons.resolved_subtype_lists[P] ? GLOB.Singletons.subtype_lists[P] : GLOB.Singletons.GetSubtypeList(P)) : list())
diff --git a/modular_bandastation/_singletons/code/repository.dm b/modular_bandastation/_singletons/code/repository.dm
new file mode 100644
index 0000000000000..007155342f2bc
--- /dev/null
+++ b/modular_bandastation/_singletons/code/repository.dm
@@ -0,0 +1,147 @@
+/repository/New()
+ return
+
+/*
+/datum/cache_entry
+ var/timestamp
+ var/data
+
+/datum/cache_entry/New()
+ timestamp = world.time
+
+/datum/cache_entry/proc/is_valid()
+ return FALSE
+
+/datum/cache_entry/valid_until/New(valid_duration)
+ ..()
+ timestamp += valid_duration
+
+/datum/cache_entry/valid_until/is_valid()
+ return world.time < timestamp
+*/
+
+
+GLOBAL_DATUM_INIT(Singletons, /repository/singletons, new)
+
+/repository/singletons
+ /// A cache of individual singletons as (/singleton/path = Instance, ...)
+ var/list/instances = list()
+
+ /// A map of (/singleton/path = TRUE, ...). Indicates whether a path has been tried for instances.
+ var/list/resolved_instances = list()
+
+ /// A cache of singleton types according to a parent type as (/singleton/path = list(/singleton/path = Instance, /singleton/path/foo = Instance, ...))
+ var/list/type_maps = list()
+
+ /// A map of (/singleton/path = TRUE, ...). Indicates whether a path has been tried for type_maps.
+ var/list/resolved_type_maps = list()
+
+ /// A cache of singleton subtypes according to a parent type as (/singleton/path = list(/singleton/path/foo = Instance, ...))
+ var/list/subtype_maps = list()
+
+ /// A map of (/singleton/path = TRUE, ...). Indicates whether a path has been tried for subtype_maps.
+ var/list/resolved_subtype_maps = list()
+
+ /// A cache of singleton types according to a parent type as (/singleton/path = list(Parent Instance, Subtype Instance, ...))
+ var/list/type_lists = list()
+
+ /// A map of (/singleton/path = TRUE, ...). Indicates whether a path has been tried for type_lists.
+ var/list/resolved_type_lists = list()
+
+ /// A cache of singleton subtypes according to a parent type as (/singleton/path = list(Subtype Instance, Subtype Instance, ...))
+ var/list/subtype_lists = list()
+
+ /// A map of (/singleton/path = TRUE, ...). Indicates whether a path has been tried for subtype_lists.
+ var/list/resolved_subtype_lists = list()
+
+
+/**
+* Get a singleton instance according to path. Creates it if necessary. Null if abstract or not a singleton.
+* Prefer the GET_SINGLETON macro to minimize proc calls.
+*/
+/repository/singletons/proc/GetInstance(datum/singleton/path)
+ if(!ispath(path, /datum/singleton))
+ return
+ if(resolved_instances[path])
+ return instances[path]
+ resolved_instances[path] = TRUE
+ if(path == initial(path.abstract_type))
+ return
+ var/datum/singleton/result = new path
+ instances[path] = result
+ result.Initialize()
+ return result
+
+
+/// Get a (path = instance) map of valid singletons according to paths.
+/repository/singletons/proc/GetMap(list/datum/singleton/paths)
+ var/list/result = list()
+ for(var/path in paths)
+ var/datum/singleton/instance = GetInstance(path)
+ if (!instance)
+ continue
+ result[path] = instance
+ return result
+
+
+/// Get a list of valid singletons according to paths.
+/repository/singletons/proc/GetList(list/datum/singleton/paths)
+ var/list/result = list()
+ for(var/path in paths)
+ var/datum/singleton/instance = GetInstance(path)
+ if(!instance)
+ continue
+ result += instance
+ return result
+
+
+/**
+* Get a (path = instance) map of valid singletons according to typesof(path).
+* Prefer the GET_SINGLETON_TYPE_MAP macro to minimize proc calls.
+*/
+/repository/singletons/proc/GetTypeMap(datum/singleton/path)
+ if(resolved_type_maps[path])
+ return type_maps[path] || list()
+ resolved_type_maps[path] = TRUE
+ var/result = GetMap(typesof(path))
+ type_maps[path] = result
+ return result
+
+
+/**
+* Get a (path = instance) map of valid singletons according to subtypesof(path).
+* Prefer the GET_SINGLETON_TYPE_MAP macro to minimize proc calls.
+*/
+/repository/singletons/proc/GetSubtypeMap(datum/singleton/path)
+ if(resolved_subtype_maps[path])
+ return subtype_maps[path] || list()
+ resolved_subtype_maps[path] = TRUE
+ var/result = GetMap(subtypesof(path))
+ subtype_maps[path] = result
+ return result
+
+
+/**
+* Get a list of valid singletons according to typesof(path).
+* Prefer the GET_SINGLETON_TYPE_LIST macro to minimize proc calls.
+*/
+/repository/singletons/proc/GetTypeList(datum/singleton/path)
+ if(resolved_type_lists[path])
+ return type_lists[path] || list()
+ resolved_type_lists[path] = TRUE
+ var/result = GetList(typesof(path))
+ type_lists[path] = result
+ return result
+
+
+/**
+* Get a list of valid singletons according to subtypesof(path).
+* Prefer the GET_SINGLETON_SUBTYPE_LIST macro to minimize proc calls.
+*/
+/repository/singletons/proc/GetSubtypeList(datum/singleton/path)
+ if(resolved_subtype_lists[path])
+ return subtype_lists[path] || list()
+ resolved_subtype_lists[path] = TRUE
+ var/result = GetList(subtypesof(path))
+ subtype_lists[path] = result
+ return result
diff --git a/modular_bandastation/_singletons/code/singletons.dm b/modular_bandastation/_singletons/code/singletons.dm
new file mode 100644
index 0000000000000..ee0bf41fcfe57
--- /dev/null
+++ b/modular_bandastation/_singletons/code/singletons.dm
@@ -0,0 +1,11 @@
+/datum/singleton
+ var/abstract_type = /datum/singleton
+
+/datum/singleton/proc/Initialize()
+ SHOULD_CALL_PARENT(TRUE)
+ SHOULD_NOT_SLEEP(TRUE)
+
+/datum/singleton/Destroy()
+ SHOULD_CALL_PARENT(FALSE)
+ . = QDEL_HINT_LETMELIVE
+ CRASH("Prevented attempt to delete a singleton instance: [src]")
diff --git a/modular_bandastation/modular_bandastation.dme b/modular_bandastation/modular_bandastation.dme
index 7540a5b77fb82..06823277ce3f3 100644
--- a/modular_bandastation/modular_bandastation.dme
+++ b/modular_bandastation/modular_bandastation.dme
@@ -2,7 +2,9 @@
#include "_modpacks.dm"
#include "_defines220/_defines220.dme"
+#include "_helpers220/_helpers220.dme"
#include "_signals220/_signals220.dme"
+#include "_singletons/_singletons.dme"
#include "aesthetics/_aesthetics.dme"
#include "ai_laws/_ai_laws.dme"
#include "barsigns/_barsigns.dme"
diff --git a/modular_bandastation/translations/code/restaurant_customer.dm b/modular_bandastation/translations/code/restaurant_customer.dm
index 1d6e3ec1728f7..e27766263e818 100644
--- a/modular_bandastation/translations/code/restaurant_customer.dm
+++ b/modular_bandastation/translations/code/restaurant_customer.dm
@@ -1,6 +1,6 @@
/datum/customer_data
speech_sound = null
- var/list/tts_seeds = list("Arthas")
+ var/list/tts_seeds = /datum/tts_seed/silero/angel
/datum/customer_data/american
found_seat_lines = list("Я надеюсь тут найдется местечко, которое выдержит мой вес.", "Надеюсь, я могу проносить сюда оружие.", "Я надеюсь здесь подают тройной жир-бургер делюкс.", "Люблю я здешнюю культуру.")
@@ -12,8 +12,7 @@
first_warning_line = "Не стоит со мной шутить!"
second_warning_line = "Последнее предупреждение, чувак! Отвали!"
self_defense_line = "РЕЖИМ ЖИРОМЕНТАЛЯ АКТИВИРОВАН!"
- tts_seeds = list("Braum", "Malfurion", "Medivh", "Ozara", "Pudge")
-
+ tts_seeds = list(/datum/tts_seed/silero/braum, /datum/tts_seed/silero/malfurion, /datum/tts_seed/silero/medivh, /datum/tts_seed/silero/ozara, /datum/tts_seed/silero/pudge)
/datum/customer_data/italian
prefix_file = "strings/names/italian_prefix.txt"
@@ -28,8 +27,7 @@
first_warning_line = "Не трогай меня, мамма-мия!"
second_warning_line = "Последнее предупреждение! Не прикасайся к моим спагетти!"
self_defense_line = "Я замешу тебя так, как моя мамма замешивала свои фирменные фрикадельки!"
- tts_seeds = list("Barbas", "Clockwerk", "Muradin", "Rasil")
-
+ tts_seeds = list(/datum/tts_seed/silero/barbas, /datum/tts_seed/silero/clockwerk, /datum/tts_seed/silero/muradin, /datum/tts_seed/silero/rasil)
/datum/customer_data/french
prefix_file = "strings/names/french_prefix.txt"
@@ -45,8 +43,7 @@
second_warning_line = "Не трогай меня, ты, грязное животное! Последнее предупреждение!"
self_defense_line = "Я сломаю тебя словно багет!"
speech_sound = null
- tts_seeds = list("Archmage", "Awilo", "Belloc", "Priest")
-
+ tts_seeds = list(/datum/tts_seed/silero/archmage, /datum/tts_seed/silero/awilo, /datum/tts_seed/silero/belloc, /datum/tts_seed/silero/priest)
/datum/customer_data/japanese
prefix_file = "strings/names/japanese_prefix.txt"
@@ -62,8 +59,7 @@
second_warning_line = "Я стану супер-сайяном, если ты снова прикоснешься ко мне! Последнее предупреждение!"
self_defense_line = "OMAE WA MO, SHINDEROU!"
speech_sound = null
- tts_seeds = list("Ahri", "Chromie", "Eudora", "Luna", "Qiyana")
-
+ tts_seeds = list(/datum/tts_seed/silero/ahri, /datum/tts_seed/silero/chromie, /datum/tts_seed/silero/eudora, /datum/tts_seed/silero/luna, /datum/tts_seed/silero/qiyana)
/datum/customer_data/japanese/salaryman
clothing_sets = list("japanese_salary")
@@ -77,8 +73,7 @@
second_warning_line = "Отстань от меня, я пытаюсь сконцентрироваться. Последнее предупреждение!"
self_defense_line = "Я не хотел, чтобы это закончилось вот так."
speech_sound = null
- tts_seeds = list("Malkoran", "Narrator", "Overseer", "Rhombus")
-
+ tts_seeds = list(/datum/tts_seed/silero/malkoran, /datum/tts_seed/silero/narrator, /datum/tts_seed/silero/overseer, /datum/tts_seed/silero/rhombus)
/datum/customer_data/moth
prefix_file = "strings/names/moth_prefix.txt"
@@ -93,8 +88,7 @@
second_warning_line = "Последнее предупреждение! Я уничтожу тебя!"
self_defense_line = "Крылатая атака!"
speech_sound = null
- tts_seeds = list("Ahri", "Chromie", "Eudora", "Luna", "Qiyana")
-
+ tts_seeds = list(/datum/tts_seed/silero/ahri, /datum/tts_seed/silero/chromie, /datum/tts_seed/silero/eudora, /datum/tts_seed/silero/luna, /datum/tts_seed/silero/qiyana)
/datum/customer_data/mexican
base_icon_state = "mexican"
@@ -110,8 +104,7 @@
second_warning_line = "Комрад, хватит значит хватит! Последнее предупреждение!"
self_defense_line = "Пришло время тебе узнать, какой из меня робот. Готов?"
speech_sound = null
- tts_seeds = list("Barney", "Batrider", "Putricide", "Soldier")
-
+ tts_seeds = list(/datum/tts_seed/silero/barney, /datum/tts_seed/silero/batrider, /datum/tts_seed/silero/putricide, /datum/tts_seed/silero/soldier)
/datum/customer_data/british
base_icon_state = "british"
@@ -121,8 +114,7 @@
second_warning_line = "И мирно вернуться в свои жилища или к своим законным делам, приложив усилия, содержащиеся в акте, изданном королём Георгом в первый год своего правления для предотвращения бунтов и мятежей. Более предупреждений не будет."
self_defense_line = "Боже, храни Королеву."
speech_sound = null
- tts_seeds = list("Ebony", "Ekko", "Emperor", "Loxley")
-
+ tts_seeds = list(/datum/tts_seed/silero/ebony, /datum/tts_seed/silero/ekko, /datum/tts_seed/silero/emperor, /datum/tts_seed/silero/loxley)
/datum/customer_data/british/gent
clothing_sets = list("british_gentleman")
@@ -156,7 +148,7 @@
second_warning_line = "Сломать-ты-так-сильно-ты-вспомнить-дни-до-этот-момент.exe: запуск..."
self_defense_line = "Я был создан, чтобы делать две вещи: заказывать еду и ломать каждую кость в твоем теле."
speech_sound = null
- tts_seeds = list("Glados")
+ tts_seeds = list(/datum/tts_seed/silero/glados)
/datum/venue/restaurant/order_food_line(order)
var/obj/item/object_to_order = order
@@ -182,4 +174,4 @@
. = ..()
var/datum/customer_data/customer_info = SSrestaurant.all_customers[customer_data]
if(customer_info)
- tts_seed = pick(customer_info.tts_seeds)
+ AddComponent(/datum/component/tts_component, pick(customer_info.tts_seeds))
diff --git a/modular_bandastation/tts/_tts.dm b/modular_bandastation/tts/_tts.dm
index bb5b70a3afb72..a230df0e0a4d0 100644
--- a/modular_bandastation/tts/_tts.dm
+++ b/modular_bandastation/tts/_tts.dm
@@ -1,4 +1,4 @@
/datum/modpack/tts
- name = "TTS Silero"
- desc = "Добавляет ТТС Силеро"
+ name = "Text-To-Speech"
+ desc = "2д космонавтики говорят вслух."
author = "furior"
diff --git a/modular_bandastation/tts/_tts.dme b/modular_bandastation/tts/_tts.dme
index 64c2f24a682d4..a75ac9b353f48 100644
--- a/modular_bandastation/tts/_tts.dme
+++ b/modular_bandastation/tts/_tts.dme
@@ -1,25 +1,28 @@
#include "_tts.dm"
-#include "code\_tts_defines.dm"
-#include "code\_tts_rust_g_ss220.dm"
-#include "code\tts_configuration.dm"
-#include "code\tts_mob_Hear.dm"
-#include "code\tts_numbers.dm"
-#include "code\tts_preferences.dm"
-#include "code\tts_provider.dm"
-#include "code\tts_seed.dm"
-#include "code\tts_sound.dm"
-#include "code\tts_sound_TEMPORARY.dm"
-#include "code\tts_subsystem.dm"
-#include "code\base_seeds\mobs\_base.dm"
-#include "code\base_seeds\mobs\alien.dm"
-#include "code\base_seeds\mobs\friendly.dm"
-#include "code\base_seeds\mobs\guardian.dm"
-#include "code\base_seeds\mobs\hostile.dm"
-#include "code\base_seeds\mobs\lavaland.dm"
-#include "code\base_seeds\mobs\other.dm"
-#include "code\base_seeds\mobs\pets.dm"
-#include "code\base_seeds\objs\objs.dm"
-#include "code\providers\silero.dm"
-#include "code\seeds\silero.dm"
-#include "code\~undefs\~tts_undefs.dm"
+#include "code/_tts_rust_g_ss220.dm"
+#include "code/hear.dm"
+#include "code/numbers.dm"
+#include "code/shell.dm"
+#include "code/SSHttp.dm"
+#include "code/tts_component.dm"
+#include "code/tts_configuration.dm"
+#include "code/tts_preferences.dm"
+#include "code/tts_provider.dm"
+#include "code/tts_seed.dm"
+#include "code/tts_subsystem.dm"
+#include "code/tts_vv.dm"
+#include "code/base_seeds/mobs/_base.dm"
+#include "code/base_seeds/mobs/alien.dm"
+#include "code/base_seeds/mobs/friendly.dm"
+#include "code/base_seeds/mobs/guardian.dm"
+#include "code/base_seeds/mobs/hostile.dm"
+#include "code/base_seeds/mobs/lavaland.dm"
+#include "code/base_seeds/mobs/other.dm"
+#include "code/base_seeds/mobs/pets.dm"
+#include "code/base_seeds/objs/objs.dm"
+#include "code/providers/silero.dm"
+#include "code/seeds/base.dm"
+#include "code/seeds/silero.dm"
+
+#include "code/~undefs/~undefs.dm"
diff --git a/modular_bandastation/tts/code/SSHttp.dm b/modular_bandastation/tts/code/SSHttp.dm
new file mode 100644
index 0000000000000..5cb9cb7564c28
--- /dev/null
+++ b/modular_bandastation/tts/code/SSHttp.dm
@@ -0,0 +1,86 @@
+SUBSYSTEM_DEF(http)
+ name = "HTTP"
+ flags = SS_TICKER | SS_BACKGROUND | SS_NO_INIT // Measure in ticks, but also only run if we have the spare CPU.
+ wait = 1
+ runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY // All the time
+ // Assuming for the worst, since only discord is hooked into this for now, but that may change
+ /// List of all async HTTP requests in the processing chain
+ var/list/datum/http_request/active_async_requests = list()
+ /// Variable to define if logging is enabled or not. Disabled by default since we know the requests the server is making. Enable with VV if you need to debug requests
+ var/logging_enabled = FALSE
+ /// Total requests the SS has processed in a round
+ var/total_requests
+
+/datum/controller/subsystem/http/PreInit()
+ . = ..()
+ rustgss220_create_async_http_client() // Open the door
+
+/datum/controller/subsystem/http/fire(resumed)
+ for(var/r in active_async_requests)
+ var/datum/http_request/req = r
+ // Check if we are complete
+ if(req.is_complete())
+ // If so, take it out the processing list
+ active_async_requests -= req
+ var/datum/http_response/res = req.into_response()
+
+ // If the request has a callback, invoke it.Async of course to avoid choking the SS
+ if(req.cb)
+ req.cb.InvokeAsync(res)
+
+ // And log the result
+ if(logging_enabled)
+ var/list/log_data = list()
+ log_data += "BEGIN ASYNC RESPONSE (ID: [req.id])"
+ if(res.errored)
+ log_data += "\t ----- RESPONSE ERRROR -----"
+ log_data += "\t [res.error]"
+ else
+ log_data += "\tResponse status code: [res.status_code]"
+ log_data += "\tResponse body: [res.body]"
+ log_data += "\tResponse headers: [json_encode(res.headers)]"
+ log_data += "END ASYNC RESPONSE (ID: [req.id])"
+ logger.Log(LOG_CATEGORY_DEBUG, log_data.Join("\n"))
+
+/**
+ * Async request creator
+ *
+ * Generates an async request, and adds it to the subsystem's processing list
+ * These should be used as they do not lock the entire DD process up as they execute inside their own thread pool inside RUSTG
+ */
+/datum/controller/subsystem/http/proc/create_async_request(method, url, body = "", list/headers, datum/callback/proc_callback)
+ var/datum/http_request/req = new()
+ req.prepare(method, url, body, headers)
+ if(proc_callback)
+ req.cb = proc_callback
+
+ // Begin it and add it to the SS active list
+ req.begin_async()
+ active_async_requests += req
+ total_requests++
+
+ if(logging_enabled)
+ // Create a log holder
+ var/list/log_data = list()
+ log_data += "BEGIN ASYNC REQUEST (ID: [req.id])"
+ log_data += "\t[uppertext(req.method)] [req.url]"
+ log_data += "\tRequest body: [req.body]"
+ log_data += "\tRequest headers: [req.headers]"
+ log_data += "END ASYNC REQUEST (ID: [req.id])"
+
+ // Write the log data
+
+ logger.Log(LOG_CATEGORY_DEBUG, log_data.Join("\n"))
+
+/**
+ * Blocking request creator
+ *
+ * Generates a blocking request, executes it, logs the info then cleanly returns the response
+ * Exists as a proof of concept, and should never be used
+ */
+/datum/controller/subsystem/http/proc/make_blocking_request(method, url, body = "", list/headers)
+ CRASH("Attempted use of a blocking HTTP request")
+
+/datum/http_request
+ /// Callback for executing after async requests. Will be called with an argument of [/datum/http_response] as first argument
+ var/datum/callback/cb
diff --git a/modular_bandastation/tts/code/_tts_rust_g_ss220.dm b/modular_bandastation/tts/code/_tts_rust_g_ss220.dm
index 5a0cd3647b25d..54599608e3cb6 100644
--- a/modular_bandastation/tts/code/_tts_rust_g_ss220.dm
+++ b/modular_bandastation/tts/code/_tts_rust_g_ss220.dm
@@ -56,3 +56,6 @@
// Text Operations //
#define rustgss220_cyrillic_to_latin(text) RUSTG_CALL(RUST_G_SS220, "cyrillic_to_latin")("[text]")
#define rustgss220_latin_to_cyrillic(text) RUSTG_CALL(RUST_G_SS220, "latin_to_cyrillic")("[text]")
+
+/proc/rustgss220_create_async_http_client() return RUSTG_CALL(RUST_G_SS220, "start_http_client")()
+/proc/rustgss220_close_async_http_client() return RUSTG_CALL(RUST_G_SS220, "shutdown_http_client")()
diff --git a/modular_bandastation/tts/code/base_seeds/mobs/_base.dm b/modular_bandastation/tts/code/base_seeds/mobs/_base.dm
index 8be816e8f22c3..cf230fb4ba01a 100644
--- a/modular_bandastation/tts/code/base_seeds/mobs/_base.dm
+++ b/modular_bandastation/tts/code/base_seeds/mobs/_base.dm
@@ -1,8 +1,13 @@
-//Fallback values for TTS voices
+// Fallback values for TTS voices
-/mob/living
- tts_seed = "Kleiner"
+/mob/living/add_tts_component()
+ AddComponent(/datum/component/tts_component)
-// /mob/living/basic
+/mob/living/basic/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/angel)
-// /mob/living/simple_animal
+/mob/living/simple_animal/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/angel)
+
+/mob/living/silicon/add_tts_component()
+ AddComponent(/datum/component/tts_component, null, TTS_TRAIT_ROBOTIZE)
diff --git a/modular_bandastation/tts/code/base_seeds/mobs/alien.dm b/modular_bandastation/tts/code/base_seeds/mobs/alien.dm
index e961a000fac1e..273c6364a82ef 100644
--- a/modular_bandastation/tts/code/base_seeds/mobs/alien.dm
+++ b/modular_bandastation/tts/code/base_seeds/mobs/alien.dm
@@ -1,11 +1,11 @@
//Aliens!
-/mob/living/carbon/alien
- tts_seed = "Ladyvashj"
+/mob/living/carbon/alien/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/ladyvashj)
-/mob/living/carbon/alien/larva
- tts_seed = "Templar"
+/mob/living/carbon/alien/larva/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/templar)
-/mob/living/carbon/alien/adult/royal/queen
- tts_seed = "Queen"
+/mob/living/carbon/alien/adult/royal/queen/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/queen)
diff --git a/modular_bandastation/tts/code/base_seeds/mobs/friendly.dm b/modular_bandastation/tts/code/base_seeds/mobs/friendly.dm
index 847713b532150..9d6c2aab0986d 100644
--- a/modular_bandastation/tts/code/base_seeds/mobs/friendly.dm
+++ b/modular_bandastation/tts/code/base_seeds/mobs/friendly.dm
@@ -1,61 +1,61 @@
//Farm and friendly creatures.
-/mob/living/basic/parrot
- tts_seed = "Sniper"
+/mob/living/basic/parrot/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/sniper)
-/mob/living/basic/pet/cat
- tts_seed = "Valerian"
+/mob/living/basic/pet/cat/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/valerian)
-/mob/living/basic/cockroach
- tts_seed = "Villagerm"
+/mob/living/basic/cockroach/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/villagerm)
-/mob/living/basic/crab
- tts_seed = "Riki"
+/mob/living/basic/crab/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/riki)
-/mob/living/basic/pet/dog
- tts_seed = "Stetmann"
+/mob/living/basic/pet/dog/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/stetmann)
-/mob/living/basic/goat
- tts_seed = "Muradin"
+/mob/living/basic/goat/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/muradin)
-/mob/living/basic/cow
- tts_seed = "Cairne"
+/mob/living/basic/cow/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/cairne)
-/mob/living/basic/chick
- tts_seed = "Meepo"
+/mob/living/basic/chick/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/meepo)
-/mob/living/basic/chicken
- tts_seed = "Windranger"
+/mob/living/basic/chicken/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/windranger)
-/mob/living/basic/pig
- tts_seed = "Anubarak"
+/mob/living/basic/pig/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/anubarak)
-/mob/living/simple_animal/hostile/retaliate/goose
- tts_seed = "pantheon"
+/mob/living/simple_animal/hostile/retaliate/goose/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/pantheon)
-/mob/living/basic/pet/fox
- tts_seed = "Barney"
+/mob/living/basic/pet/fox/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/barney)
-/mob/living/basic/frog
- tts_seed = "pantheon"
+/mob/living/basic/frog/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/pantheon)
-/mob/living/basic/lizard
- tts_seed = "Shaker"
+/mob/living/basic/lizard/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/shaker)
-/mob/living/basic/mouse
- tts_seed = "Gyro"
+/mob/living/basic/mouse/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/gyro)
-/mob/living/basic/mouse/white
- tts_seed = "Meepo"
+/mob/living/basic/mouse/white/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/meepo)
-/mob/living/basic/mouse/brown
- tts_seed = "Clockwerk"
+/mob/living/basic/mouse/brown/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/clockwerk)
-/mob/living/basic/pet/penguin
- tts_seed = "Narrator"
+/mob/living/basic/pet/penguin/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/narrator)
-/mob/living/basic/sloth
- tts_seed = "Peon"
+/mob/living/basic/sloth/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/peon)
-/mob/living/basic/butterfly
- tts_seed = "Meepo"
+/mob/living/basic/butterfly/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/meepo)
diff --git a/modular_bandastation/tts/code/base_seeds/mobs/guardian.dm b/modular_bandastation/tts/code/base_seeds/mobs/guardian.dm
index f313ce7fbff43..1d0c28c6fb87e 100644
--- a/modular_bandastation/tts/code/base_seeds/mobs/guardian.dm
+++ b/modular_bandastation/tts/code/base_seeds/mobs/guardian.dm
@@ -1,16 +1,16 @@
//Guardians
-/mob/living/basic/guardian
- tts_seed = "Earth"
+/mob/living/basic/guardian/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/earth)
-/mob/living/basic/guardian/assassin
- tts_seed = "Spy"
+/mob/living/basic/guardian/assassin/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/spy)
-/mob/living/basic/guardian/lightning
- tts_seed = "Archmage"
+/mob/living/basic/guardian/lightning/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/archmage)
-/mob/living/basic/guardian/protector
- tts_seed = "Caime"
+/mob/living/basic/guardian/protector/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/cairne)
-/mob/living/basic/guardian/standard
- tts_seed = "Heavy"
+/mob/living/basic/guardian/standard/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/heavy)
diff --git a/modular_bandastation/tts/code/base_seeds/mobs/hostile.dm b/modular_bandastation/tts/code/base_seeds/mobs/hostile.dm
index 8a151180fcd1f..f0798bf83a647 100644
--- a/modular_bandastation/tts/code/base_seeds/mobs/hostile.dm
+++ b/modular_bandastation/tts/code/base_seeds/mobs/hostile.dm
@@ -1,46 +1,46 @@
//Hostile mobs
-/mob/living/basic/blob_minion
- tts_seed = "Earth"
+/mob/living/basic/blob_minion/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/earth)
-/mob/living/basic/clockwork_marauder
- tts_seed = "Earth"
+/mob/living/basic/clockwork_marauder/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/earth)
-/mob/living/basic/cortical_borer
- tts_seed = "Gman_e2"
+/mob/living/basic/cortical_borer/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/gman_e2)
-/mob/living/basic/morph
- tts_seed = "Treant"
+/mob/living/basic/morph/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/treant)
-/mob/living/basic/revenant
- tts_seed = "Sylvanas"
+/mob/living/basic/revenant/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/sylvanas)
-/mob/living/basic/demon
- tts_seed = "Mannoroth"
+/mob/living/basic/demon/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/mannoroth)
-/mob/living/basic/construct
- tts_seed = "Acolyte"
+/mob/living/basic/construct/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/acolyte)
-/mob/living/basic/construct/wraith
- tts_seed = "Kelthuzad"
+/mob/living/basic/construct/wraith/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/kelthuzad)
-/mob/living/basic/snake
- tts_seed = "Ladyvashj"
+/mob/living/basic/snake/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/ladyvashj)
-/mob/living/basic/bear
- tts_seed = "Shaker"
+/mob/living/basic/bear/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/shaker)
-/mob/living/basic/carp
- tts_seed = "Peon"
+/mob/living/basic/carp/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/peon)
-/mob/living/basic/carp/mega
- tts_seed = "Shaker"
+/mob/living/basic/carp/mega/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/shaker)
-/mob/living/basic/creature
- tts_seed = "Earth"
+/mob/living/basic/creature/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/earth)
-/mob/living/basic/giant_spider
- tts_seed = "Anubarak"
+/mob/living/basic/giant_spider/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/anubarak)
-/mob/living/simple_animal/hostile
- tts_seed = "Vort_e2"
+/mob/living/simple_animal/hostile/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/vort_e2)
diff --git a/modular_bandastation/tts/code/base_seeds/mobs/lavaland.dm b/modular_bandastation/tts/code/base_seeds/mobs/lavaland.dm
index 72118bd8eb424..3ce943172e402 100644
--- a/modular_bandastation/tts/code/base_seeds/mobs/lavaland.dm
+++ b/modular_bandastation/tts/code/base_seeds/mobs/lavaland.dm
@@ -1,34 +1,34 @@
//Lavaland mobs and megafauna
-/mob/living/simple_animal/hostile/megafauna
- tts_seed = "Mannoroth"
+/mob/living/simple_animal/hostile/megafauna/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/mannoroth)
-/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner
- tts_seed = "Chen"
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/chen)
-/mob/living/basic/mining/basilisk
- tts_seed = "Antimage"
+/mob/living/basic/mining/basilisk/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/antimage)
-/mob/living/basic/mining/goliath/ancient
- tts_seed = "Bloodseeker"
+/mob/living/basic/mining/goliath/ancient/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/bloodseeker)
-/mob/living/basic/mining/hivelord
- tts_seed = "Ladyvashj"
+/mob/living/basic/mining/hivelord/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/ladyvashj)
-/mob/living/basic/mining/legion
- tts_seed = "Bloodseeker"
+/mob/living/basic/mining/legion/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/bloodseeker)
-/mob/living/basic/mining/legion/big
- tts_seed = "Mannoroth"
+/mob/living/basic/mining/legion/big/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/mannoroth)
-/mob/living/simple_animal/hostile/asteroid/elite/broodmother
- tts_seed = "Azalina"
+/mob/living/simple_animal/hostile/asteroid/elite/broodmother/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/azalina)
-/mob/living/simple_animal/hostile/asteroid/elite/herald
- tts_seed = "Abathur"
+/mob/living/simple_animal/hostile/asteroid/elite/herald/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/abathur)
-/mob/living/simple_animal/hostile/asteroid/elite/legionnaire
- tts_seed = "Volibear"
+/mob/living/simple_animal/hostile/asteroid/elite/legionnaire/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/volibear)
-/mob/living/simple_animal/hostile/asteroid/elite/pandora
- tts_seed = "Zyra"
+/mob/living/simple_animal/hostile/asteroid/elite/pandora/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/zyra)
diff --git a/modular_bandastation/tts/code/base_seeds/mobs/other.dm b/modular_bandastation/tts/code/base_seeds/mobs/other.dm
index 98abf06f165b1..66fd6367032c3 100644
--- a/modular_bandastation/tts/code/base_seeds/mobs/other.dm
+++ b/modular_bandastation/tts/code/base_seeds/mobs/other.dm
@@ -1,22 +1,22 @@
//Uncategorized mobs
-/mob/living/silicon/ai
- tts_seed = "Glados"
+/mob/living/silicon/ai/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/glados, TTS_TRAIT_ROBOTIZE)
-/obj/item/nullrod/scythe/talking
- tts_seed = "Sylvanas"
+/obj/item/nullrod/scythe/talking/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/sylvanas)
-/mob/living/basic/shade
- tts_seed = "Kelthuzad"
+/mob/living/basic/shade/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/kelthuzad)
-/mob/living/simple_animal/bot
- tts_seed = null
+/mob/living/simple_animal/bot/add_tts_component()
+ return
-/mob/living/basic/slime
- tts_seed = "Chen"
+/mob/living/basic/slime/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/chen)
-/mob/living/carbon/human/species/monkey
- tts_seed = "Sniper"
+/mob/living/carbon/human/species/monkey/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/sniper)
-/mob/living/carbon/human/species/monkey/punpun
- tts_seed = "Chen"
+/mob/living/carbon/human/species/monkey/punpun/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/chen)
diff --git a/modular_bandastation/tts/code/base_seeds/mobs/pets.dm b/modular_bandastation/tts/code/base_seeds/mobs/pets.dm
index 5b8551cfc9618..738082880ceb0 100644
--- a/modular_bandastation/tts/code/base_seeds/mobs/pets.dm
+++ b/modular_bandastation/tts/code/base_seeds/mobs/pets.dm
@@ -1,7 +1,7 @@
//All named pets
-/mob/living/basic/giant_spider/sgt_araneus
- tts_seed = "Anubarak"
+/mob/living/basic/giant_spider/sgt_araneus/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/anubarak)
-/mob/living/basic/parrot/poly
- tts_seed = "Gyro"
+/mob/living/basic/parrot/poly/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/gyro)
diff --git a/modular_bandastation/tts/code/base_seeds/objs/objs.dm b/modular_bandastation/tts/code/base_seeds/objs/objs.dm
index bf110d0326075..8dbea91cf248b 100644
--- a/modular_bandastation/tts/code/base_seeds/objs/objs.dm
+++ b/modular_bandastation/tts/code/base_seeds/objs/objs.dm
@@ -1,26 +1,23 @@
-/obj/machinery
- tts_seed = "Glados"
+/obj/machinery/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/glados)
-/obj/machinery/computer
- tts_seed = null
+/obj/machinery/computer/add_tts_component()
+ return
-/obj/machinery/modular_computer
- tts_seed = null
+/obj/machinery/modular_computer/add_tts_component()
+ return
-/obj/machinery/rnd
- tts_seed = null
+/obj/machinery/rnd/add_tts_component()
+ return
-/obj/machinery/autolathe
- tts_seed = null
+/obj/machinery/autolathe/add_tts_component()
+ return
-/obj/machinery/mecha_part_fabricator
- tts_seed = null
+/obj/machinery/mecha_part_fabricator/add_tts_component()
+ return
-/obj/item/modular_computer
- tts_seed = null
+/obj/item/modular_computer/add_tts_component()
+ return
-/obj/item/taperecorder
- tts_seed = "Xenia"
-
-/obj/item/ttsdevice
- tts_seed = "Xenia"
+/obj/item/taperecorder/add_tts_component()
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/xenia)
diff --git a/modular_bandastation/tts/code/hear.dm b/modular_bandastation/tts/code/hear.dm
new file mode 100644
index 0000000000000..bdb5e768ad446
--- /dev/null
+++ b/modular_bandastation/tts/code/hear.dm
@@ -0,0 +1,11 @@
+/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods, message_range)
+ . = ..()
+ if(!.)
+ return
+ speaker.cast_tts(src, raw_message, effect = radio_freq ? /datum/singleton/sound_effect/radio : null)
+
+/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods, message_range)
+ . = ..()
+ if(!.)
+ return
+ speaker.cast_tts(src, raw_message, effect = radio_freq ? /datum/singleton/sound_effect/radio : null)
diff --git a/modular_bandastation/tts/code/tts_numbers.dm b/modular_bandastation/tts/code/numbers.dm
similarity index 94%
rename from modular_bandastation/tts/code/tts_numbers.dm
rename to modular_bandastation/tts/code/numbers.dm
index c330ce48a285a..ed41e245dfcf3 100644
--- a/modular_bandastation/tts/code/tts_numbers.dm
+++ b/modular_bandastation/tts/code/numbers.dm
@@ -12,11 +12,7 @@
if(num.cache["[n]"])
return num.cache["[n]"]
- var/result
- if(decimal)
- result = num.decimal2words(n)
- else
- result = num.int2words(n)
+ var/result = decimal ? num.decimal2words(n) : num.int2words(n)
result = " [result] "
num.cache["[n]"] = result
@@ -84,12 +80,7 @@
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) )
+ var/list/data = use_teens ? list(list(teens, 10), list(hundreds, 1000)) : list(list(units, 10), list(tens, 100), list(hundreds, 1000))
for(var/list in data)
var/names = list[1]
diff --git a/modular_bandastation/tts/code/providers/silero.dm b/modular_bandastation/tts/code/providers/silero.dm
index bfd611760b7ee..3c5a46406a0b1 100644
--- a/modular_bandastation/tts/code/providers/silero.dm
+++ b/modular_bandastation/tts/code/providers/silero.dm
@@ -6,10 +6,10 @@
if(throttle_check())
return FALSE
- var/api_url = "http://s2.ss220.club:9999/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
@@ -22,16 +22,8 @@
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)
+
+ SShttp.create_async_request(RUSTG_HTTP_METHOD_POST, CONFIG_GET(string/tts_api_url_silero), json_encode(req_body), list("content-type" = "application/json"), proc_callback)
return TRUE
diff --git a/modular_bandastation/tts/code/seeds/base.dm b/modular_bandastation/tts/code/seeds/base.dm
new file mode 100644
index 0000000000000..dbfe0e6af47d6
--- /dev/null
+++ b/modular_bandastation/tts/code/seeds/base.dm
@@ -0,0 +1,7 @@
+/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/required_donator_level = 0
diff --git a/modular_bandastation/tts/code/seeds/silero.dm b/modular_bandastation/tts/code/seeds/silero.dm
index 5f83cb4078cd6..d85746ec8fa6b 100644
--- a/modular_bandastation/tts/code/seeds/silero.dm
+++ b/modular_bandastation/tts/code/seeds/silero.dm
@@ -6,48 +6,56 @@
value = "arthas"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/kelthuzad
name = "Kelthuzad"
value = "kelthuzad"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/anubarak
name = "Anubarak"
value = "anubarak"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 2
/datum/tts_seed/silero/thrall
name = "Thrall"
value = "thrall"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/grunt
name = "Grunt"
value = "grunt"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/cairne
name = "Cairne"
value = "cairne"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 3
/datum/tts_seed/silero/rexxar
name = "Rexxar"
value = "rexxar"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/uther
name = "Uther"
value = "uther"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/jaina
name = "Jaina"
@@ -66,6 +74,7 @@
value = "garithos"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/maiev
name = "Maiev"
@@ -96,6 +105,7 @@
value = "illidan"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/ladyvashj
name = "Ladyvashj"
@@ -120,6 +130,7 @@
value = "villagerm"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/xenia
name = "Xenia"
@@ -132,24 +143,28 @@
value = "illidan_f"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/peon
name = "Peon"
value = "peon"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/chen
name = "Chen"
value = "chen"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/dread_bm
name = "Dread_bm"
value = "dread_bm"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/sylvanas
name = "Sylvanas"
@@ -162,12 +177,14 @@
value = "priest"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/acolyte
name = "Acolyte"
value = "acolyte"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/muradin
name = "Muradin"
@@ -186,6 +203,7 @@
value = "mannoroth"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/sorceress
name = "Sorceress"
@@ -198,6 +216,7 @@
value = "peasant"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/alyx
name = "Alyx"
@@ -234,7 +253,7 @@
value = "raynor"
category = TTS_CATEGORY_STARCRAFT
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/kerrigan
name = "Kerrigan"
@@ -247,24 +266,28 @@
value = "tusk"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/earth
name = "Earth"
value = "earth"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/wraith
name = "Wraith"
value = "wraith"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/meepo
name = "Meepo"
value = "meepo"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_ANY
+ required_donator_level = 1
/datum/tts_seed/silero/lina
name = "Lina"
@@ -277,6 +300,7 @@
value = "bristle"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/gyro
name = "Gyro"
@@ -289,30 +313,35 @@
value = "treant"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/lancer
name = "Lancer"
value = "lancer"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/clockwerk
name = "Clockwerk"
value = "clockwerk"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/batrider
name = "Batrider"
value = "batrider"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/kotl
name = "Kotl"
value = "kotl"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/kunkka
name = "Kunkka"
@@ -325,19 +354,21 @@
value = "pudge"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/juggernaut
name = "Juggernaut"
value = "juggernaut"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/vort_e2
name = "Vort_e2"
value = "vort_e2"
category = TTS_CATEGORY_HALFLIFE2
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/luna
name = "Luna"
@@ -350,30 +381,35 @@
value = "omni"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/sniper
name = "Sniper"
value = "sniper"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 2
/datum/tts_seed/silero/skywrath
name = "Skywrath"
value = "skywrath"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/bounty
name = "Bounty"
value = "bounty"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_ANY
+ required_donator_level = 1
/datum/tts_seed/silero/huskar
name = "Huskar"
value = "huskar"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/windranger
name = "Windranger"
@@ -386,6 +422,7 @@
value = "bloodseeker"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/templar
name = "Templar"
@@ -398,12 +435,14 @@
value = "ranger"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
/datum/tts_seed/silero/shaker
name = "Shaker"
value = "shaker"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/mortred
name = "Mortred"
@@ -422,43 +461,49 @@
value = "storm"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/tide
name = "Tide"
value = "tide"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/evelynn
name = "Evelynn"
value = "evelynn"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/riki
name = "Riki"
value = "riki"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/antimage
name = "Antimage"
value = "antimage"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_ANY
+ required_donator_level = 1
/datum/tts_seed/silero/witchdoctor
name = "Witchdoctor"
value = "witchdoctor"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/doom
name = "Doom"
value = "doom"
category = TTS_CATEGORY_DOTA2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/yuumi
name = "Yuumi"
@@ -471,26 +516,28 @@
value = "bandit"
category = TTS_CATEGORY_STALKER
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/pantheon
name = "pantheon"
value = "pantheon"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/tychus
name = "Tychus"
value = "tychus"
category = TTS_CATEGORY_STARCRAFT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/breen
name = "Breen"
value = "breen"
category = TTS_CATEGORY_HALFLIFE2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/kleiner
name = "Kleiner"
@@ -503,12 +550,14 @@
value = "father"
category = TTS_CATEGORY_HALFLIFE2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/tosh
name = "Tosh"
value = "tosh"
category = TTS_CATEGORY_STARCRAFT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/stetmann
name = "Stetmann"
@@ -527,19 +576,21 @@
value = "swann"
category = TTS_CATEGORY_STARCRAFT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/hill
name = "Hill"
value = "hill"
category = TTS_CATEGORY_STARCRAFT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/gman_e2
name = "Gman_e2"
value = "gman_e2"
category = TTS_CATEGORY_HALFLIFE2
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/valerian
name = "Valerian"
@@ -552,6 +603,7 @@
value = "gman"
category = TTS_CATEGORY_HALFLIFE2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/vort
name = "Vort"
@@ -570,6 +622,7 @@
value = "dornan"
category = TTS_CATEGORY_FALLOUT2
gender = TTS_GENDER_MALE
+ required_donator_level = 2
/datum/tts_seed/silero/elder
name = "Elder"
@@ -594,12 +647,14 @@
value = "decker"
category = TTS_CATEGORY_FALLOUT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/dick
name = "Dick"
value = "dick"
category = TTS_CATEGORY_FALLOUT2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/officer
name = "Officer"
@@ -612,30 +667,35 @@
value = "frank"
category = TTS_CATEGORY_FALLOUT2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/gizmo
name = "Gizmo"
value = "gizmo"
category = TTS_CATEGORY_FALLOUT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/hakunin
name = "Hakunin"
value = "hakunin"
category = TTS_CATEGORY_FALLOUT2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/harold
name = "Harold"
value = "harold"
category = TTS_CATEGORY_FALLOUT2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/harry
name = "Harry"
value = "harry"
category = TTS_CATEGORY_FALLOUT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/jain
name = "Jain"
@@ -648,6 +708,7 @@
value = "maxson"
category = TTS_CATEGORY_FALLOUT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/killian
name = "Killian"
@@ -666,12 +727,14 @@
value = "lieutenant"
category = TTS_CATEGORY_FALLOUT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/loxley
name = "Loxley"
value = "loxley"
category = TTS_CATEGORY_FALLOUT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/lynette
name = "Lynette"
@@ -684,24 +747,28 @@
value = "marcus"
category = TTS_CATEGORY_FALLOUT2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/master
name = "Master"
value = "master"
category = TTS_CATEGORY_FALLOUT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/morpheus
name = "Morpheus"
value = "morpheus"
category = TTS_CATEGORY_FALLOUT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/myron
name = "Myron"
value = "myron"
category = TTS_CATEGORY_FALLOUT2
gender = TTS_GENDER_ANY
+ required_donator_level = 1
/datum/tts_seed/silero/nicole
name = "Nicole"
@@ -714,6 +781,7 @@
value = "overseer"
category = TTS_CATEGORY_FALLOUT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/rhombus
name = "Rhombus"
@@ -726,12 +794,14 @@
value = "set"
category = TTS_CATEGORY_FALLOUT
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/sulik
name = "Sulik"
value = "sulik"
category = TTS_CATEGORY_FALLOUT2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/tandi
name = "Tandi"
@@ -750,18 +820,21 @@
value = "dude"
category = TTS_CATEGORY_POSTAL2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/archmage
name = "Archmage"
value = "archmage"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/demoman
name = "Demoman"
value = "demoman"
category = TTS_CATEGORY_TEAMFORTRESS2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/engineer
name = "Engineer"
@@ -780,6 +853,7 @@
value = "medic"
category = TTS_CATEGORY_TEAMFORTRESS2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/scout
name = "Scout"
@@ -792,12 +866,14 @@
value = "sniper_tf"
category = TTS_CATEGORY_TEAMFORTRESS2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/soldier
name = "Soldier"
value = "soldier"
category = TTS_CATEGORY_TEAMFORTRESS2
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/spy
name = "Spy"
@@ -810,18 +886,21 @@
value = "admiral"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/alchemist
name = "Alchemist"
value = "alchemist"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 2
/datum/tts_seed/silero/archimonde
name = "Archimonde"
value = "archimonde"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 2
/datum/tts_seed/silero/breaker
name = "Breaker"
@@ -834,6 +913,7 @@
value = "captain"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/dryad
name = "Dryad"
@@ -846,24 +926,28 @@
value = "elf_eng"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/footman
name = "Footman"
value = "footman"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/grom
name = "Grom"
value = "grom"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/hh
name = "Hh"
value = "hh"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/huntress
name = "Huntress"
@@ -876,18 +960,21 @@
value = "keeper"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/naga_m
name = "Naga_m"
value = "naga_m"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/naga_rg
name = "Naga_rg"
value = "naga_rg"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/peasant_w
name = "Peasant_w"
@@ -900,6 +987,7 @@
value = "rifleman"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/satyr
name = "Satyr"
@@ -918,2413 +1006,2415 @@
value = "voljin"
category = TTS_CATEGORY_WARCRAFT3
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/sidorovich
name = "Sidorovich"
value = "sidorovich"
category = TTS_CATEGORY_STALKER
gender = TTS_GENDER_MALE
+ required_donator_level = 1
/datum/tts_seed/silero/p3
name = "P3"
value = "p3"
category = TTS_CATEGORY_ATOMIC_HEART
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/hraz
name = "Hraz"
value = "hraz"
category = TTS_CATEGORY_ATOMIC_HEART
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/tereshkova
name = "Tereshkova"
value = "tereshkova"
category = TTS_CATEGORY_ATOMIC_HEART
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/babazina
name = "Babazina"
value = "babazina"
category = TTS_CATEGORY_ATOMIC_HEART
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/darius
name = "Darius"
value = "darius"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/trundle
name = "Trundle"
value = "trundle"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/garen
name = "Garen"
value = "garen"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/kled
name = "Kled"
value = "kled"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/ekko
name = "Ekko"
value = "ekko"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/volibear
name = "Volibear"
value = "volibear"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/samira
name = "Samira"
value = "samira"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/swain
name = "Swain"
value = "swain"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/udyr
name = "Udyr"
value = "udyr"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/dr_mundo
name = "Dr_mundo"
value = "dr_mundo"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/graves
name = "Graves"
value = "graves"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/rakan
name = "Rakan"
value = "rakan"
category = TTS_CATEGORY_LOL
- gender = TTS_GENDER_FEMALE
- donator_level = 0
+ gender = TTS_GENDER_MALE
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/gangplank
name = "Gangplank"
value = "gangplank"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/riven
name = "Riven"
value = "riven"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/katarina
name = "Katarina"
value = "katarina"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/ahri
name = "Ahri"
value = "ahri"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/ornn
name = "Ornn"
value = "ornn"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/braum
name = "Braum"
value = "braum"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/fizz
name = "Fizz"
value = "fizz"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/draven
name = "Draven"
value = "draven"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/qiyana
name = "Qiyana"
value = "qiyana"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/ksante
name = "Ksante"
value = "ksante"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/talon
name = "Talon"
value = "talon"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/shyvana
name = "Shyvana"
value = "shyvana"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/zenyatta
name = "Zenyatta"
value = "zenyatta"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/kiriko
name = "Kiriko"
value = "kiriko"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/hanzo
name = "Hanzo"
value = "hanzo"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/roadhog
name = "Roadhog"
value = "roadhog"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/sigma
name = "Sigma"
value = "sigma"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/soldier_76
name = "Soldier_76"
value = "soldier_76"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/junkrat
name = "Junkrat"
value = "junkrat"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/tracer
name = "Tracer"
value = "tracer"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/genji
name = "Genji"
value = "genji"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/echo
name = "Echo"
value = "echo"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/sojourn
name = "Sojourn"
value = "sojourn"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/winston
name = "Winston"
value = "winston"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/reaper
name = "Reaper"
value = "reaper"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/training_robot
name = "Training_robot"
value = "training_robot"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/esbern
name = "Esbern"
value = "esbern"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/m_argo
name = "M_argo"
value = "m_argo"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/m_coward
name = "M_coward"
value = "m_coward"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/farkas
name = "Farkas"
value = "farkas"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/m_citizen
name = "M_citizen"
value = "m_citizen"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/odahviing
name = "Odahviing"
value = "odahviing"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/kodlak
name = "Kodlak"
value = "kodlak"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/emperor
name = "Emperor"
value = "emperor"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/hagraven
name = "Hagraven"
value = "hagraven"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/nazir
name = "Nazir"
value = "nazir"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/dremora
name = "Dremora"
value = "dremora"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/alduin
name = "Alduin"
value = "alduin"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/malkoran
name = "Malkoran"
value = "malkoran"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/barbas
name = "Barbas"
value = "barbas"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/hermaeus
name = "Hermaeus"
value = "hermaeus"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/hakon
name = "Hakon"
value = "hakon"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/rita
name = "Rita"
value = "rita"
category = TTS_CATEGORY_RITA
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/barman
name = "Barman"
value = "barman"
category = TTS_CATEGORY_STALKER
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/bridger2
name = "Bridger2"
value = "bridger2"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/bridger3
name = "Bridger3"
value = "bridger3"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/cannibal3
name = "Cannibal3"
value = "cannibal3"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/bridger1
name = "Bridger1"
value = "bridger1"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/cannibal2
name = "Cannibal2"
value = "cannibal2"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/slave1
name = "Slave1"
value = "slave1"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/slave3
name = "Slave3"
value = "slave3"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/mira
name = "Mira"
value = "mira"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/valeera
name = "Valeera"
value = "valeera"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/rehgar
name = "Rehgar"
value = "rehgar"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/yrel
name = "Yrel"
value = "yrel"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/volskaya
name = "Volskaya"
value = "volskaya"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/necromancer
name = "Necromancer"
value = "necromancer"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/zuljin
name = "Zuljin"
value = "zuljin"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/samuro
name = "Samuro"
value = "samuro"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/tyrael
name = "Tyrael"
value = "tyrael"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/athena
name = "Athena"
value = "athena"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/default
name = "Default"
value = "default"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/chromie
name = "Chromie"
value = "chromie"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/orphea
name = "Orphea"
value = "orphea"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/adjutant
name = "Adjutant"
value = "adjutant"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/vanndara
name = "Vanndara"
value = "vanndara"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/mechatassadar
name = "Mechatassadar"
value = "mechatassadar"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/blackheart
name = "Blackheart"
value = "blackheart"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/olaf
name = "Olaf"
value = "olaf"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/alarak
name = "Alarak"
value = "alarak"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/dva
name = "Dva"
value = "dva"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/toy18
name = "Toy18"
value = "toy18"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 2
/datum/tts_seed/silero/lucio
name = "Lucio"
value = "lucio"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/angel
name = "Angel"
value = "angel"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/thunderking
name = "Thunderking"
value = "thunderking"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/dr_boom
name = "Dr_boom"
value = "dr_boom"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/hooktusk
name = "Hooktusk"
value = "hooktusk"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/sinclari
name = "Sinclari"
value = "sinclari"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/kazakus
name = "Kazakus"
value = "kazakus"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/moroes
name = "Moroes"
value = "moroes"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/maiev_hs
name = "Maiev_hs"
value = "maiev_hs"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/zentimo
name = "Zentimo"
value = "zentimo"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/rastakhan
name = "Rastakhan"
value = "rastakhan"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/innkeeper
name = "Innkeeper"
value = "innkeeper"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/togwaggle
name = "Togwaggle"
value = "togwaggle"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/biggs
name = "Biggs"
value = "biggs"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/brann
name = "Brann"
value = "brann"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 2
/datum/tts_seed/silero/siamat
name = "Siamat"
value = "siamat"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/omnotron
name = "Omnotron"
value = "omnotron"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/putricide
name = "Putricide"
value = "putricide"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/khadgar
name = "Khadgar"
value = "khadgar"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/zoie
name = "Zoie"
value = "zoie"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/azalina
name = "Azalina"
value = "azalina"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/chu
name = "Chu"
value = "chu"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/tekahn
name = "Tekahn"
value = "tekahn"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/sthara
name = "Sthara"
value = "sthara"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/dovo
name = "Dovo"
value = "dovo"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/shaw
name = "Shaw"
value = "shaw"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/greymane
name = "Greymane"
value = "greymane"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/willow
name = "Willow"
value = "willow"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/haro
name = "Haro"
value = "haro"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/hagatha
name = "Hagatha"
value = "hagatha"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/reno
name = "Reno"
value = "reno"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/ozara
name = "Ozara"
value = "ozara"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/loti
name = "Loti"
value = "loti"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/tarkus
name = "Tarkus"
value = "tarkus"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/voone
name = "Voone"
value = "voone"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/tala
name = "Tala"
value = "tala"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/edra
name = "Edra"
value = "edra"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/myra
name = "Myra"
value = "myra"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/smiggs
name = "Smiggs"
value = "smiggs"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/timothy
name = "Timothy"
value = "timothy"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/wendy
name = "Wendy"
value = "wendy"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/hannigan
name = "Hannigan"
value = "hannigan"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/vargoth
name = "Vargoth"
value = "vargoth"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/jolene
name = "Jolene"
value = "jolene"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/kyriss
name = "Kyriss"
value = "kyriss"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/saurfang
name = "Saurfang"
value = "saurfang"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/kizi
name = "Kizi"
value = "kizi"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/slate
name = "Slate"
value = "slate"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/hesutu
name = "Hesutu"
value = "hesutu"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/hancho
name = "Hancho"
value = "hancho"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/gnomenapper
name = "Gnomenapper"
value = "gnomenapper"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/valdera
name = "Valdera"
value = "valdera"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/disidra
name = "Disidra"
value = "disidra"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/omu
name = "Omu"
value = "omu"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/floop
name = "Floop"
value = "floop"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/belloc
name = "Belloc"
value = "belloc"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/xurios
name = "Xurios"
value = "xurios"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/wagtoggle
name = "Wagtoggle"
value = "wagtoggle"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/belnaara
name = "Belnaara"
value = "belnaara"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/lilayell
name = "Lilayell"
value = "lilayell"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/candlebeard
name = "Candlebeard"
value = "candlebeard"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/awilo
name = "Awilo"
value = "awilo"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/marei
name = "Marei"
value = "marei"
category = TTS_CATEGORY_HEARTHSTONE
- gender = TTS_GENDER_FEMALE
- donator_level = 0
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
/datum/tts_seed/silero/applebough
name = "Applebough"
value = "applebough"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/lazul
name = "Lazul"
value = "lazul"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/arwyn
name = "Arwyn"
value = "arwyn"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/glowtron
name = "Glowtron"
value = "glowtron"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/cardish
name = "Cardish"
value = "cardish"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/robold
name = "Robold"
value = "robold"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/malfurion
name = "Malfurion"
value = "malfurion"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/deathwhisper
name = "Deathwhisper"
value = "deathwhisper"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/janna
name = "Janna"
value = "janna"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/cassiopeia
name = "Cassiopeia"
value = "cassiopeia"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/taliyah
name = "Taliyah"
value = "taliyah"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/neeko
name = "Neeko"
value = "neeko"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/taric
name = "Taric"
value = "taric"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/akshan
name = "Akshan"
value = "akshan"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/tristana
name = "Tristana"
value = "tristana"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/sylas
name = "Sylas"
value = "sylas"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/sejuani
name = "Sejuani"
value = "sejuani"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/anivia
name = "Anivia"
value = "anivia"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/vayne
name = "Vayne"
value = "vayne"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/karma
name = "Karma"
value = "karma"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/nilah
name = "Nilah"
value = "nilah"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/olaf_lol
name = "Olaf_lol"
value = "olaf_lol"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/quinn
name = "Quinn"
value = "quinn"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/lissandra
name = "Lissandra"
value = "lissandra"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/hecarim
name = "Hecarim"
value = "hecarim"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/vi
name = "Vi"
value = "vi"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/zyra
name = "Zyra"
value = "zyra"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/zac
name = "Zac"
value = "zac"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/moira
name = "Moira"
value = "moira"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/ashe
name = "Ashe"
value = "ashe"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/brigitte
name = "Brigitte"
value = "brigitte"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/mercy
name = "Mercy"
value = "mercy"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/lucio_ov
name = "Lucio_ov"
value = "lucio_ov"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 2
/datum/tts_seed/silero/symmetra
name = "Symmetra"
value = "symmetra"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/zarya
name = "Zarya"
value = "zarya"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/cassidy
name = "Cassidy"
value = "cassidy"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/baptiste
name = "Baptiste"
value = "baptiste"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/junker_queen
name = "Junker_queen"
value = "junker_queen"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/doomfist
name = "Doomfist"
value = "doomfist"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/pharah
name = "Pharah"
value = "pharah"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/sombra
name = "Sombra"
value = "sombra"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/ana
name = "Ana"
value = "ana"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/widowmaker
name = "Widowmaker"
value = "widowmaker"
category = TTS_CATEGORY_OVERWATCH
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/harbor
name = "Harbor"
value = "harbor"
category = TTS_CATEGORY_VALORANT
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/sage
name = "Sage"
value = "sage"
category = TTS_CATEGORY_VALORANT
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/brimstone
name = "Brimstone"
value = "brimstone"
category = TTS_CATEGORY_VALORANT
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/sova
name = "Sova"
value = "sova"
category = TTS_CATEGORY_VALORANT
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/f_shrill
name = "F_shrill"
value = "f_shrill"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/m_soldier
name = "M_soldier"
value = "m_soldier"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/sven
name = "Sven"
value = "sven"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/eorlund
name = "Eorlund"
value = "eorlund"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/lydia
name = "Lydia"
value = "lydia"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/motierre
name = "Motierre"
value = "motierre"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/tullius
name = "Tullius"
value = "tullius"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/festus
name = "Festus"
value = "festus"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/olava
name = "Olava"
value = "olava"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/hadvar
name = "Hadvar"
value = "hadvar"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 2
/datum/tts_seed/silero/arngeir
name = "Arngeir"
value = "arngeir"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/nazeem
name = "Nazeem"
value = "nazeem"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/falion
name = "Falion"
value = "falion"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/f_coward
name = "F_coward"
value = "f_coward"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/m_commoner
name = "M_commoner"
value = "m_commoner"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/elisif
name = "Elisif"
value = "elisif"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/paarthurnax
name = "Paarthurnax"
value = "paarthurnax"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/grelka
name = "Grelka"
value = "grelka"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/f_commoner
name = "F_commoner"
value = "f_commoner"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/ebony
name = "Ebony"
value = "ebony"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/ulfric
name = "Ulfric"
value = "ulfric"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/farengar
name = "Farengar"
value = "farengar"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/astrid
name = "Astrid"
value = "astrid"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/brynjolf
name = "Brynjolf"
value = "brynjolf"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/maven
name = "Maven"
value = "maven"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_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 = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/delphine
name = "Delphine"
value = "delphine"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/grelod
name = "Grelod"
value = "grelod"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/tolfdir
name = "Tolfdir"
value = "tolfdir"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/m_bandit
name = "M_bandit"
value = "m_bandit"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/karliah
name = "Karliah"
value = "karliah"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/felldir
name = "Felldir"
value = "felldir"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/ancano
name = "Ancano"
value = "ancano"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/mercer
name = "Mercer"
value = "mercer"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/vex
name = "Vex"
value = "vex"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/mirabelle
name = "Mirabelle"
value = "mirabelle"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/aventus
name = "Aventus"
value = "aventus"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/tsun
name = "Tsun"
value = "tsun"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/elenwen
name = "Elenwen"
value = "elenwen"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/gormlaith
name = "Gormlaith"
value = "gormlaith"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/dragon
name = "Dragon"
value = "dragon"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/overwatch
name = "Overwatch"
value = "overwatch"
category = TTS_CATEGORY_HALFLIFE2
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/zak
name = "Zak"
value = "zak"
category = TTS_CATEGORY_EVILISLANDS
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/merc2
name = "Merc2"
value = "merc2"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/forest1
name = "Forest1"
value = "forest1"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/bandit3
name = "Bandit3"
value = "bandit3"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/forest2
name = "Forest2"
value = "forest2"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/merc1
name = "Merc1"
value = "merc1"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/bandit2
name = "Bandit2"
value = "bandit2"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/forest3
name = "Forest3"
value = "forest3"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/tribal3
name = "Tribal3"
value = "tribal3"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/slave2
name = "Slave2"
value = "slave2"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/miller
name = "Miller"
value = "miller"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/krest
name = "Krest"
value = "krest"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/tribal1
name = "Tribal1"
value = "tribal1"
category = TTS_CATEGORY_METRO
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/abathur
name = "Abathur"
value = "abathur"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/erik
name = "Erik"
value = "erik"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/varian
name = "Varian"
value = "varian"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/anduin
name = "Anduin"
value = "anduin"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/deckard
name = "Deckard"
value = "deckard"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/malfurion_h
name = "Malfurion_h"
value = "malfurion_h"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/demonhunter
name = "Demonhunter"
value = "demonhunter"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/demon
name = "Demon"
value = "demon"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 2
/datum/tts_seed/silero/ladyofthorns
name = "Ladyofthorns"
value = "ladyofthorns"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/barbarian
name = "Barbarian"
value = "barbarian"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/crusader
name = "Crusader"
value = "crusader"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/whitemane
name = "Whitemane"
value = "whitemane"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/nexushunter
name = "Nexushunter"
value = "nexushunter"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/greymane_h
name = "Greymane_h"
value = "greymane_h"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/gardensdayannouncer
name = "Gardensdayannouncer"
value = "gardensdayannouncer"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/drekthar
name = "Drekthar"
value = "drekthar"
category = TTS_CATEGORY_HEROESOFTHESTORM
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/squeamlish
name = "Squeamlish"
value = "squeamlish"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/dagg
name = "Dagg"
value = "dagg"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/brukan
name = "Brukan"
value = "brukan"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/bolan
name = "Bolan"
value = "bolan"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/goya
name = "Goya"
value = "goya"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/stargazer
name = "Stargazer"
value = "stargazer"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/eudora
name = "Eudora"
value = "eudora"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/mozaki
name = "Mozaki"
value = "mozaki"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/katrana
name = "Katrana"
value = "katrana"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 1
/datum/tts_seed/silero/malacrass
name = "Malacrass"
value = "malacrass"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/elise
name = "Elise"
value = "elise"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/flark
name = "Flark"
value = "flark"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/rhogi
name = "Rhogi"
value = "rhogi"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/gallywix
name = "Gallywix"
value = "gallywix"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/talanji
name = "Talanji"
value = "talanji"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 3
/datum/tts_seed/silero/tierra
name = "Tierra"
value = "tierra"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/zenda
name = "Zenda"
value = "zenda"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/baechao
name = "Baechao"
value = "baechao"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/lilian
name = "Lilian"
value = "lilian"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/aranna
name = "Aranna"
value = "aranna"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/oshi
name = "Oshi"
value = "oshi"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/norroa
name = "Norroa"
value = "norroa"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/turalyon
name = "Turalyon"
value = "turalyon"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/aki
name = "Aki"
value = "aki"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/lunara
name = "Lunara"
value = "lunara"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/bob
name = "Bob"
value = "bob"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/illucia
name = "Illucia"
value = "illucia"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/yrel_hs
name = "Yrel_hs"
value = "yrel_hs"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/fireheart
name = "Fireheart"
value = "fireheart"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/lanathel
name = "Lanathel"
value = "lanathel"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_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 = 0
+ required_donator_level = 3
/datum/tts_seed/silero/draemus
name = "Draemus"
value = "draemus"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/rasil
name = "Rasil"
value = "rasil"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/kalec
name = "Kalec"
value = "kalec"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/karastamper
name = "Karastamper"
value = "karastamper"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/george
name = "George"
value = "george"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/pollark
name = "Pollark"
value = "pollark"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/stelina
name = "Stelina"
value = "stelina"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/kasa
name = "Kasa"
value = "kasa"
category = TTS_CATEGORY_HEARTHSTONE
- gender = TTS_GENDER_FEMALE
- donator_level = 0
+ gender = TTS_GENDER_ANY
+ required_donator_level = 1
/datum/tts_seed/silero/whirt
name = "Whirt"
value = "whirt"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/anarii
name = "Anarii"
value = "anarii"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/ilza
name = "Ilza"
value = "ilza"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/avozu
name = "Avozu"
value = "avozu"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/jeklik
name = "Jeklik"
value = "jeklik"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/zibb
name = "Zibb"
value = "zibb"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/thrud
name = "Thrud"
value = "thrud"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_MALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/isiset
name = "Isiset"
value = "isiset"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_FEMALE
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/akazamzarak
name = "Akazamzarak"
value = "akazamzarak"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/arha
name = "Arha"
@@ -3361,221 +3451,1413 @@
value = "senna"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/nunu
name = "Nunu"
value = "nunu"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/ryze
name = "Ryze"
value = "ryze"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/yone
name = "Yone"
value = "yone"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/sett
name = "Sett"
value = "sett"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/camille
name = "Camille"
value = "camille"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/lee_sin
name = "Lee_sin"
value = "lee_sin"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/kayle
name = "Kayle"
value = "kayle"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/azir
name = "Azir"
value = "azir"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/tryndamere
name = "Tryndamere"
value = "tryndamere"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/nami
name = "Nami"
value = "nami"
category = TTS_CATEGORY_LOL
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/delvin
name = "Delvin"
value = "delvin"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/cicero
name = "Cicero"
value = "cicero"
category = TTS_CATEGORY_SKYRIM
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/linzi
name = "Linzi"
value = "linzi"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/cache
name = "Cache"
value = "cache"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/cravitz
name = "Cravitz"
value = "cravitz"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 3
/datum/tts_seed/silero/lady_vashj
name = "Lady_vashj"
value = "lady_vashj"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/dendrologist
name = "Dendrologist"
value = "dendrologist"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/jythiros
name = "Jythiros"
value = "jythiros"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/draan
name = "Draan"
value = "draan"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/rikkar
name = "Rikkar"
value = "rikkar"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/splintergraft
name = "Splintergraft"
value = "splintergraft"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/malchezaar
name = "Malchezaar"
value = "malchezaar"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/taskmaster
name = "Taskmaster"
value = "taskmaster"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/oxana
name = "Oxana"
value = "oxana"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/inara
name = "Inara"
value = "inara"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/ivan
name = "Ivan"
value = "ivan"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/kazamon
name = "Kazamon"
value = "kazamon"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/albin
name = "Albin"
value = "albin"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/ammunae
name = "Ammunae"
value = "ammunae"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
/datum/tts_seed/silero/illidara
name = "Illidara"
value = "illidara"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 2
/datum/tts_seed/silero/nici
name = "Nici"
value = "nici"
category = TTS_CATEGORY_HEARTHSTONE
gender = TTS_GENDER_ANY
- donator_level = 0
+ required_donator_level = 1
+
+/datum/tts_seed/silero/byasha
+ name = "Byasha"
+ value = "byasha"
+ category = TTS_CATEGORY_TINYBUNNY
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/cerys
+ name = "Cerys"
+ value = "cerys"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/philippa
+ name = "Philippa"
+ value = "philippa"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/oldnekro
+ name = "Oldnekro"
+ value = "oldnekro"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/lambert
+ name = "Lambert"
+ value = "lambert"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/shani
+ name = "Shani"
+ value = "shani"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/anton
+ name = "Anton"
+ value = "anton"
+ category = TTS_CATEGORY_TINYBUNNY
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/dolg1
+ name = "Dolg1"
+ value = "dolg1"
+ category = TTS_CATEGORY_STALKER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/guru
+ name = "Guru"
+ value = "guru"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/lugos
+ name = "Lugos"
+ value = "lugos"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/karina
+ name = "Karina"
+ value = "karina"
+ category = TTS_CATEGORY_TINYBUNNY
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/ewald
+ name = "Ewald"
+ value = "ewald"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/mirror
+ name = "Mirror"
+ value = "mirror"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/noble
+ name = "Noble"
+ value = "noble"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/huber
+ name = "Huber"
+ value = "huber"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/wywern
+ name = "Wywern"
+ value = "wywern"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/avallach
+ name = "Avallach"
+ value = "avallach"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/semen
+ name = "Semen"
+ value = "semen"
+ category = TTS_CATEGORY_TINYBUNNY
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/all_elder
+ name = "All_elder"
+ value = "all_elder"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/nsheriff
+ name = "Nsheriff"
+ value = "nsheriff"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/orcc
+ name = "Orcc"
+ value = "orcc"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/clerk
+ name = "Clerk"
+ value = "clerk"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/witch
+ name = "Witch"
+ value = "witch"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/deva
+ name = "Deva"
+ value = "deva"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/coach
+ name = "Coach"
+ value = "coach"
+ category = TTS_CATEGORY_LEFT4DEAD
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/dictor
+ name = "Dictor"
+ value = "dictor"
+ category = TTS_CATEGORY_PORTAL2
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/monolith2
+ name = "Monolith2"
+ value = "monolith2"
+ category = TTS_CATEGORY_STALKER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/invoker
+ name = "Invoker"
+ value = "invoker"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/goblin
+ name = "Goblin"
+ value = "goblin"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/annah
+ name = "Annah"
+ value = "annah"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/patrick
+ name = "Patrick"
+ value = "patrick"
+ category = TTS_CATEGORY_SPONGEBOB
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/spongebob
+ name = "Spongebob"
+ value = "spongebob"
+ category = TTS_CATEGORY_SPONGEBOB
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/kapitan
+ name = "Kapitan"
+ value = "kapitan"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/karh
+ name = "Karh"
+ value = "karh"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/lydia_tb
+ name = "Lydia_tb"
+ value = "lydia_tb"
+ category = TTS_CATEGORY_TINYBUNNY
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/silencer
+ name = "Silencer"
+ value = "silencer"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/sheriff
+ name = "Sheriff"
+ value = "sheriff"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/lycan
+ name = "Lycan"
+ value = "lycan"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/cirilla
+ name = "Cirilla"
+ value = "cirilla"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/legends
+ name = "Legends"
+ value = "legends"
+ category = TTS_CATEGORY_STALKER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/monolith1
+ name = "Monolith1"
+ value = "monolith1"
+ category = TTS_CATEGORY_STALKER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/trapper
+ name = "Trapper"
+ value = "trapper"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/mirana
+ name = "Mirana"
+ value = "mirana"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 3
+
+/datum/tts_seed/silero/glav
+ name = "Glav"
+ value = "glav"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/syanna
+ name = "Syanna"
+ value = "syanna"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/regis
+ name = "Regis"
+ value = "regis"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/dazzle
+ name = "Dazzle"
+ value = "dazzle"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/mthief
+ name = "Mthief"
+ value = "mthief"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/guillaume
+ name = "Guillaume"
+ value = "guillaume"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/vivienne
+ name = "Vivienne"
+ value = "vivienne"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/plankton
+ name = "Plankton"
+ value = "plankton"
+ category = TTS_CATEGORY_SPONGEBOB
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/rochelle
+ name = "Rochelle"
+ value = "rochelle"
+ category = TTS_CATEGORY_LEFT4DEAD
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/vor
+ name = "Vor"
+ value = "vor"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/grandmother
+ name = "Grandmother"
+ value = "grandmother"
+ category = TTS_CATEGORY_TINYBUNNY
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/dolg2
+ name = "Dolg2"
+ value = "dolg2"
+ category = TTS_CATEGORY_STALKER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/junboy
+ name = "Junboy"
+ value = "junboy"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/shopper
+ name = "Shopper"
+ value = "shopper"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/papillon
+ name = "Papillon"
+ value = "papillon"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/cm
+ name = "Cm"
+ value = "cm"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/vesemir
+ name = "Vesemir"
+ value = "vesemir"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/kate
+ name = "Kate"
+ value = "kate"
+ category = TTS_CATEGORY_TINYBUNNY
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/polina
+ name = "Polina"
+ value = "polina"
+ category = TTS_CATEGORY_TINYBUNNY
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/crach
+ name = "Crach"
+ value = "crach"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/gryphon
+ name = "Gryphon"
+ value = "gryphon"
+ category = TTS_CATEGORY_WARCRAFT3
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/zeus
+ name = "Zeus"
+ value = "zeus"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/iz
+ name = "Iz"
+ value = "iz"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/geralt
+ name = "Geralt"
+ value = "geralt"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 3
+
+/datum/tts_seed/silero/stories
+ name = "Stories"
+ value = "stories"
+ category = TTS_CATEGORY_STALKER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/nekro
+ name = "Nekro"
+ value = "nekro"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/hwleader
+ name = "Hwleader"
+ value = "hwleader"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/yennefer
+ name = "Yennefer"
+ value = "yennefer"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/hero
+ name = "Hero"
+ value = "hero"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/baratrum
+ name = "Baratrum"
+ value = "baratrum"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/ellis
+ name = "Ellis"
+ value = "ellis"
+ category = TTS_CATEGORY_LEFT4DEAD
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/udalryk
+ name = "Udalryk"
+ value = "udalryk"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/dad
+ name = "Dad"
+ value = "dad"
+ category = TTS_CATEGORY_TINYBUNNY
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/smith
+ name = "Smith"
+ value = "smith"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/romka
+ name = "Romka"
+ value = "romka"
+ category = TTS_CATEGORY_TINYBUNNY
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/abaddon
+ name = "Abaddon"
+ value = "abaddon"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/eskel
+ name = "Eskel"
+ value = "eskel"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/freedom
+ name = "Freedom"
+ value = "freedom"
+ category = TTS_CATEGORY_STALKER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/magess
+ name = "Magess"
+ value = "magess"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_ANY
+ required_donator_level = 1
+
+/datum/tts_seed/silero/nalo
+ name = "Nalo"
+ value = "nalo"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/dandelion
+ name = "Dandelion"
+ value = "dandelion"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 3
+
+/datum/tts_seed/silero/palmerin
+ name = "Palmerin"
+ value = "palmerin"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/olgierd
+ name = "Olgierd"
+ value = "olgierd"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/d_sven
+ name = "D_sven"
+ value = "d_sven"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+ required_donator_level = 3
+
+/datum/tts_seed/silero/triss
+ name = "Triss"
+ value = "triss"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_FEMALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/monkey
+ name = "Monkey"
+ value = "monkey"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/squidward
+ name = "Squidward"
+ value = "squidward"
+ category = TTS_CATEGORY_SPONGEBOB
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/ember
+ name = "Ember"
+ value = "ember"
+ category = TTS_CATEGORY_DOTA2
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/ycf
+ name = "Ycf"
+ value = "ycf"
+ category = TTS_CATEGORY_EVILISLANDS
+ gender = TTS_GENDER_MALE
+ required_donator_level = 2
+
+/datum/tts_seed/silero/nick
+ name = "Nick"
+ value = "nick"
+ category = TTS_CATEGORY_LEFT4DEAD
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/hjalmar
+ name = "Hjalmar"
+ value = "hjalmar"
+ category = TTS_CATEGORY_WITCHER
+ gender = TTS_GENDER_MALE
+ required_donator_level = 1
+
+/datum/tts_seed/silero/gale
+ name = "Gale"
+ value = "en_Gale"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/jaheira
+ name = "Jaheira"
+ value = "en_Jaheira"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/laezel
+ name = "Laezel"
+ value = "en_Laezel"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/karlach
+ name = "Karlach"
+ value = "en_Karlach"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/shadowheart
+ name = "Shadowheart"
+ value = "en_Shadowheart"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/wyll
+ name = "Wyll"
+ value = "en_Wyll"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/minthara
+ name = "Minthara"
+ value = "en_Minthara"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/minsc
+ name = "Minsc"
+ value = "en_Minsc"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/astarion
+ name = "Astarion"
+ value = "en_Astarion"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/halsin
+ name = "Halsin"
+ value = "en_Halsin"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/emperor_bg3
+ name = "Mind_Flayer_Emperor"
+ value = "en_Emperor"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/ketheric
+ name = "Ketheric"
+ value = "en_Ketheric"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/gortash
+ name = "Gortash"
+ value = "en_Gortash"
+ category = TTS_CATEGORY_BALDURS_GATE_3
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/cave_johnson
+ name = "Cave_Johnson"
+ value = "portal_cave_johnson"
+ category = TTS_CATEGORY_PORTAL
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/shredder
+ name = "Shredder"
+ value = "Ninja_Turtles_shredder"
+ category = TTS_CATEGORY_TMNT
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/han_solo
+ name = "Han_Solo"
+ value = "Star_Wars_Han_Solo"
+ category = TTS_CATEGORY_STAR_WARS
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/darth_sidious
+ name = "Darth_Sidious"
+ value = "Star_Wars_Darth_Sidious"
+ category = TTS_CATEGORY_STAR_WARS
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/luke_skywalker
+ name = "Luke_Skywalker"
+ value = "Star_Wars_Luke_Skywalker"
+ category = TTS_CATEGORY_STAR_WARS
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/yoda
+ name = "Yoda"
+ value = "Star_Wars_Yoda"
+ category = TTS_CATEGORY_STAR_WARS
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/darth_vader
+ name = "Darth_Vader"
+ value = "Star_Wars_Darth_Vader"
+ category = TTS_CATEGORY_STAR_WARS
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/obiwan_kenobi
+ name = "Obi-wan_Kenobi"
+ value = "Star_Wars_Obi-Wan_Kenobi"
+ category = TTS_CATEGORY_STAR_WARS
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/anakin_skywalker
+ name = "Anakin_Skywalker"
+ value = "Star_Wars_Anakin_Skywalker"
+ category = TTS_CATEGORY_STAR_WARS
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/optimus_prime
+ name = "Optimus_Prime"
+ value = "Transformers_War_of_Cybertron_optimusprime"
+ category = TTS_CATEGORY_TRANSFORMERS
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/megatron
+ name = "Megatron"
+ value = "Transformers_War_of_Cybertron_megatron"
+ category = TTS_CATEGORY_TRANSFORMERS
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/soundwave
+ name = "Soundwave"
+ value = "Transformers_War_of_Cybertron_soundwave"
+ category = TTS_CATEGORY_TRANSFORMERS
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/aragorn
+ name = "Aragorn"
+ value = "The_Lord_of_the_Rings_Aragorn"
+ category = TTS_CATEGORY_LOTR
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/elrond
+ name = "Elrond"
+ value = "The_Lord_of_the_Rings_Elrond"
+ category = TTS_CATEGORY_LOTR
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/gandalf
+ name = "Gandalf"
+ value = "The_Lord_of_the_Rings_Gandalf"
+ category = TTS_CATEGORY_LOTR
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/gimli
+ name = "Gimli"
+ value = "The_Lord_of_the_Rings_Gimli"
+ category = TTS_CATEGORY_LOTR
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/gollum
+ name = "Gollum"
+ value = "The_Lord_of_the_Rings_Gollum"
+ category = TTS_CATEGORY_LOTR
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/legolas
+ name = "Legolas"
+ value = "The_Lord_of_the_Rings_Legolas"
+ category = TTS_CATEGORY_LOTR
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/gingerbread_man
+ name = "Gingerbread_Man"
+ value = "Srek_Gingerbread_Man"
+ category = TTS_CATEGORY_SHREK
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/fiona
+ name = "Fiona"
+ value = "Srek_Fiona"
+ category = TTS_CATEGORY_SHREK
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/donkey
+ name = "Donkey"
+ value = "Srek_Donkey"
+ category = TTS_CATEGORY_SHREK
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/fairy_godmother
+ name = "Fairy_Godmother"
+ value = "Srek_Fairy_Godmother"
+ category = TTS_CATEGORY_SHREK
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/srek_king
+ name = "King"
+ value = "Srek_King"
+ category = TTS_CATEGORY_SHREK
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/srek_narrator
+ name = "Shrek_Narrator"
+ value = "Srek_Narrator"
+ category = TTS_CATEGORY_SHREK
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/puss_in_boots
+ name = "Puss_in_Boots"
+ value = "Srek_Puss_in_Boots"
+ category = TTS_CATEGORY_SHREK
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/shrek
+ name = "Shrek"
+ value = "Srek_Shrek"
+ category = TTS_CATEGORY_SHREK
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/jack_sparrow
+ name = "Jack_Sparrow"
+ value = "Pirats_of_the_caribbean_Jack_Sparrow"
+ category = TTS_CATEGORY_POTC
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/barbossa
+ name = "Barbossa"
+ value = "Pirats_of_the_caribbean_Barbossa"
+ category = TTS_CATEGORY_POTC
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/tiadalma
+ name = "Tiadalma"
+ value = "Pirats_of_the_caribbean_Tiadalma"
+ category = TTS_CATEGORY_POTC
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/davy_jones
+ name = "Davy_Jones"
+ value = "Pirats_of_the_caribbean_Davy_Jones"
+ category = TTS_CATEGORY_POTC
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sirius_black
+ name = "Sirius_Black"
+ value = "Harry_Potter_Sirius_Black"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/dobby
+ name = "Dobby"
+ value = "Harry_Potter_Dobby"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/severus_snape_film
+ name = "Severus_snape_film"
+ value = "Harry_Potter_Severus_Snape_film"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/harry_potter
+ name = "Harry_Potter"
+ value = "Harry_Potter_Harry_Potter"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/dumbledore
+ name = "Albus_Dumbledore"
+ value = "Harry_Potter_Albus_Dumbledore"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/voldemort
+ name = "Voldemort"
+ value = "Harry_Potter_Lord_Voldemort"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/severus_snape
+ name = "Severus_Snape"
+ value = "Harry_Potter_Severus_Snape"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/flitwick
+ name = "Filius_Flitwick"
+ value = "Harry_Potter_Filius_Flitwick"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/minerva_mcgonagall
+ name = "Minnerva_McGonagall"
+ value = "Harry_Potter_Minerva_McGonagall"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/horace_slughorn
+ name = "Horace_Slughorn"
+ value = "Harry_Potter_Horace_Slughorn"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/cedric
+ name = "Cedric"
+ value = "Harry_Potter_Cedric"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/alastor
+ name = "Alastor_Mad-eye_Moody"
+ value = "Harry_Potter_Alastor_Mad-Eye_Moody"
+ category = TTS_CATEGORY_HARRY_POTTER
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/x3_betty
+ name = "Betty"
+ value = "X3_reunion_Betty"
+ category = TTS_CATEGORY_X3
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/overlord_gnarl
+ name = "Gnarl"
+ value = "Overlord_2_Gnarl"
+ category = TTS_CATEGORY_OVERLORD2
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/tony_stark
+ name = "Tony_Stark"
+ value = "Marvel_Tony_Stark"
+ category = TTS_CATEGORY_MARVEL
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sabellian
+ name = "Sabellian"
+ value = "Dragons_Sabellian"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/ysera
+ name = "Ysera"
+ value = "Dragons_Ysera"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/malygos_wotlk
+ name = "Malygos_wotlk"
+ value = "Dragons_MalygosWrath_of_the_Lich_King"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/ebyssian
+ name = "Ebyssian"
+ value = "Dragons_Ebyssian"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/deathwing
+ name = "Deathwing"
+ value = "Dragons_Deathwing"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/nozdormu
+ name = "Nozdormu"
+ value = "Dragons_Nozdormu"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/malygos
+ name = "Malygos"
+ value = "Dragons_Malygos"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/calderax
+ name = "Calderax"
+ value = "Draconids_Calderax"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/bazentus
+ name = "Bazentus"
+ value = "Draconids_Bazentus"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/kazra
+ name = "Kazra"
+ value = "Draconids_Kazra"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/seltherex
+ name = "Seltherex"
+ value = "Draconids_Seltherex"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/sendrax
+ name = "Sendrax"
+ value = "Draconids_Sendrax"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/evantkis
+ name = "Evantkis"
+ value = "Draconids_Evantkis"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/drine
+ name = "Drine"
+ value = "Draconids_Drine"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/lethanak
+ name = "Lethanak"
+ value = "Draconids_Lethanak"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/wrathion_echo
+ name = "Wrathion_echo"
+ value = "Dragons2_Wrathion_echo"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/alexstraza
+ name = "Alexstraza"
+ value = "Dragons2_Alexstraza"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/kalecgos
+ name = "Kalecgos"
+ value = "Dragons2_Kalecgos"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/wrathion
+ name = "Wrathion"
+ value = "Dragons2_Wrathion"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/kalechos_echo
+ name = "Kalecgos_echo"
+ value = "Dragons2_Kalecgos_echo"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/alextraza_echo
+ name = "Alextraza_echo"
+ value = "Dragons2_Alextraza_echo"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/neltharion_echo
+ name = "Neltharion_echo"
+ value = "Dragons2_Neltharion_echo"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/wrathion_deathwing
+ name = "Wration_Deathwing"
+ value = "Dragons2_Wrathion_Deathwing"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/neltharion
+ name = "Neltharion"
+ value = "Dragons2_Neltharion"
+ category = TTS_CATEGORY_WOW
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/livsy
+ name = "Livsy"
+ value = "Treasure_Island_Livsy"
+ category = TTS_CATEGORY_TREASURE_ISLAND
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sp_brother
+ name = "sp_brother"
+ value = "slovo_patsana_brother"
+ category = TTS_CATEGORY_BOYS_WORD
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sp_koschei
+ name = "sp_koschei"
+ value = "slovo_patsana_koschei"
+ category = TTS_CATEGORY_BOYS_WORD
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sp_marat
+ name = "sp_marat"
+ value = "slovo_patsana_marat"
+ category = TTS_CATEGORY_BOYS_WORD
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sp_angry_cop
+ name = "sp_angry_cop"
+ value = "slovo_patsana_angry_cop"
+ category = TTS_CATEGORY_BOYS_WORD
+ gender = TTS_GENDER_MALE
+
+/datum/tts_seed/silero/sp_cop
+ name = "sp_cop"
+ value = "slovo_patsana_cop"
+ category = TTS_CATEGORY_BOYS_WORD
+ gender = TTS_GENDER_FEMALE
+
+/datum/tts_seed/silero/sp_main
+ name = "sp_main"
+ value = "slovo_patsana_main"
+ category = TTS_CATEGORY_BOYS_WORD
+ gender = TTS_GENDER_MALE
diff --git a/modular_bandastation/tts/code/shell.dm b/modular_bandastation/tts/code/shell.dm
new file mode 100644
index 0000000000000..fb6ffeb98da39
--- /dev/null
+++ b/modular_bandastation/tts/code/shell.dm
@@ -0,0 +1,61 @@
+#define SHELLEO_ERRORLEVEL 1
+#define SHELLEO_STDOUT 2
+#define SHELLEO_STDERR 3
+
+#define SHELLEO_NAME "data/shelleo."
+#define SHELLEO_ERR ".err"
+#define SHELLEO_OUT ".out"
+
+/proc/apply_sound_effect(datum/singleton/sound_effect/effect, filename_input, filename_output)
+ if(!effect)
+ CRASH("Invalid sound effect chosen.")
+
+ var/taskset
+ CONFIG_GET(string/ffmpeg_cpuaffinity)
+ if(CONFIG_GET(string/ffmpeg_cpuaffinity))
+ taskset = "taskset -ac [CONFIG_GET(string/ffmpeg_cpuaffinity)]"
+
+ var/command = {"[taskset] ffmpeg -y -hide_banner -loglevel error -i [filename_input] -filter:a "[effect.ffmpeg_arguments]" [filename_output]"}
+ var/list/output = world.shelleo(command)
+
+ var/errorlevel = output[SHELLEO_ERRORLEVEL]
+ var/stdout = output[SHELLEO_STDOUT]
+ var/stderr = output[SHELLEO_STDERR]
+ if(errorlevel)
+ log_runtime("Error: apply_sound_effect([effect.suffix], [filename_input], [filename_output]) - See debug logs.")
+ logger.Log(LOG_CATEGORY_DEBUG, "apply_sound_effect([effect.suffix], [filename_input], [filename_output]) STDOUT: [stdout]")
+ logger.Log(LOG_CATEGORY_DEBUG, "apply_sound_effect([effect.suffix], [filename_input], [filename_output]) STDERR: [stderr]")
+ return FALSE
+ return TRUE
+
+/datum/singleton/sound_effect
+ var/suffix
+ var/ffmpeg_arguments
+
+/datum/singleton/sound_effect/radio
+ suffix = "_radio"
+ ffmpeg_arguments = "highpass=f=1000, lowpass=f=3000, acrusher=1:1:50:0:log"
+
+/datum/singleton/sound_effect/robot
+ suffix = "_robot"
+ ffmpeg_arguments = "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"
+
+/datum/singleton/sound_effect/radio_robot
+ suffix = "_radio_robot"
+ ffmpeg_arguments = "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"
+
+/datum/singleton/sound_effect/megaphone
+ suffix = "_megaphone"
+ ffmpeg_arguments = "highpass=f=500, lowpass=f=4000, volume=volume=10, acrusher=1:1:45:0:log"
+
+/datum/singleton/sound_effect/megaphone_robot
+ suffix = "_megaphone_robot"
+ ffmpeg_arguments = "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"
+
+#undef SHELLEO_ERRORLEVEL
+#undef SHELLEO_STDOUT
+#undef SHELLEO_STDERR
+
+#undef SHELLEO_NAME
+#undef SHELLEO_ERR
+#undef SHELLEO_OUT
diff --git a/modular_bandastation/tts/code/sound/radio_chatter.ogg b/modular_bandastation/tts/code/sound/radio_chatter.ogg
new file mode 100644
index 0000000000000..6e5b3ecfbfe24
Binary files /dev/null and b/modular_bandastation/tts/code/sound/radio_chatter.ogg differ
diff --git a/modular_bandastation/tts/code/tts_component.dm b/modular_bandastation/tts/code/tts_component.dm
new file mode 100644
index 0000000000000..28edbfdd6d17a
--- /dev/null
+++ b/modular_bandastation/tts/code/tts_component.dm
@@ -0,0 +1,158 @@
+/datum/component/tts_component
+ var/datum/tts_seed/tts_seed
+ var/list/traits = list()
+
+/datum/component/tts_component/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_ATOM_TTS_SEED_CHANGE, PROC_REF(tts_seed_change))
+ RegisterSignal(parent, COMSIG_ATOM_TTS_CAST, PROC_REF(cast_tts))
+ RegisterSignal(parent, COMSIG_ATOM_TTS_TRAIT_ADD, PROC_REF(tts_trait_add))
+ RegisterSignal(parent, COMSIG_ATOM_TTS_TRAIT_REMOVE, PROC_REF(tts_trait_remove))
+
+/datum/component/tts_component/UnregisterFromParent()
+ UnregisterSignal(parent, COMSIG_ATOM_TTS_SEED_CHANGE)
+ UnregisterSignal(parent, COMSIG_ATOM_TTS_CAST)
+ UnregisterSignal(parent, COMSIG_ATOM_TTS_TRAIT_ADD)
+ UnregisterSignal(parent, COMSIG_ATOM_TTS_TRAIT_REMOVE)
+
+/datum/component/tts_component/Initialize(datum/tts_seed/new_tts_seed, ...)
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+ if(ispath(new_tts_seed) && SStts220.tts_seeds[initial(new_tts_seed.name)])
+ new_tts_seed = SStts220.tts_seeds[initial(new_tts_seed.name)]
+ if(istype(new_tts_seed))
+ tts_seed = new_tts_seed
+ if(!tts_seed)
+ tts_seed = get_random_tts_seed_by_gender()
+ if(!tts_seed) // Something went terribly wrong
+ return COMPONENT_INCOMPATIBLE
+ if(length(args) > 1)
+ for(var/trait in 2 to length(args))
+ traits += args[trait]
+
+/datum/component/tts_component/proc/return_tts_seed()
+ SIGNAL_HANDLER
+ return tts_seed
+
+/datum/component/tts_component/proc/select_tts_seed(mob/chooser, silent_target = FALSE, override = FALSE, list/new_traits = null)
+ if(!chooser)
+ if(ismob(parent))
+ chooser = parent
+ else
+ return null
+
+ var/atom/being_changed = parent
+ var/static/tts_test_str = "Так звучит мой голос."
+ var/datum/tts_seed/new_tts_seed
+
+ if(chooser == being_changed)
+ var/datum/preferences/prefs = chooser.client.prefs
+ var/prefs_tts_seed = prefs?.read_preference(/datum/preference/text/tts_seed)
+ if(being_changed.gender == prefs?.read_preference(/datum/preference/choiced/gender))
+ if(tgui_alert(chooser, "Оставляем голос вашего персонажа [prefs?.read_preference(/datum/preference/name/real_name)] - [prefs_tts_seed]?", "Выбор голоса", "Нет", "Да") == "Да")
+ if(!SStts220.tts_seeds[prefs_tts_seed])
+ to_chat(chooser, span_warning("Отсутствует tts_seed для значения \"[prefs_tts_seed]\". Текущий голос - [tts_seed]"))
+ return null
+ new_tts_seed = SStts220.tts_seeds[prefs_tts_seed]
+ if(new_traits)
+ traits = new_traits
+ INVOKE_ASYNC(SStts220, TYPE_PROC_REF(/datum/controller/subsystem/tts220, get_tts), null, chooser, tts_test_str, new_tts_seed, FALSE, get_effect())
+ return new_tts_seed
+
+ var/tts_seeds
+ var/list/tts_seeds_by_gender = SStts220.get_tts_by_gender(being_changed.gender)
+ if(!length(tts_seeds_by_gender))
+ to_chat(chooser, span_warning("Не удалось найти пол для голоса! Текущий голос - [tts_seed.name]"))
+ return null
+ if(check_rights(R_ADMIN, FALSE, chooser) || override || !ismob(being_changed))
+ tts_seeds = tts_seeds_by_gender
+ else
+ tts_seeds = tts_seeds_by_gender && SStts220.get_available_seeds(being_changed) // && for lists means intersection
+
+ var/new_tts_seed_key
+ new_tts_seed_key = tgui_input_list(chooser, "Выберите голос персонажа", "Преобразуем голос", tts_seeds, tts_seed.name)
+ if(!new_tts_seed_key || !SStts220.tts_seeds[new_tts_seed_key])
+ to_chat(chooser, span_warning("Что-то пошло не так с выбором голоса. Текущий голос - [tts_seed.name]"))
+ return null
+
+ new_tts_seed = SStts220.tts_seeds[new_tts_seed_key]
+ if(new_traits)
+ traits = new_traits
+
+ if(!silent_target && being_changed != chooser && ismob(being_changed))
+ INVOKE_ASYNC(SStts220, TYPE_PROC_REF(/datum/controller/subsystem/tts220, get_tts), null, being_changed, tts_test_str, new_tts_seed, FALSE, get_effect())
+
+ if(chooser)
+ INVOKE_ASYNC(SStts220, TYPE_PROC_REF(/datum/controller/subsystem/tts220, get_tts), null, chooser, tts_test_str, new_tts_seed, FALSE, get_effect())
+
+ return new_tts_seed
+
+/datum/component/tts_component/proc/tts_seed_change(atom/being_changed, mob/chooser, override = FALSE, list/new_traits = null)
+ set waitfor = FALSE
+ var/datum/tts_seed/new_tts_seed = select_tts_seed(chooser = chooser, override = override, new_traits = new_traits)
+ if(!new_tts_seed)
+ return null
+ tts_seed = new_tts_seed
+
+/datum/component/tts_component/proc/get_random_tts_seed_by_gender()
+ var/atom/being_changed = parent
+ var/tts_choice = SStts220.pick_tts_seed_by_gender(being_changed.gender)
+ var/datum/tts_seed/seed = SStts220.tts_seeds[tts_choice]
+ if(!seed)
+ return null
+ return seed
+
+/datum/component/tts_component/proc/get_effect(effect)
+ . = effect
+ switch(.)
+ if(null)
+ if(TTS_TRAIT_ROBOTIZE in traits)
+ return /datum/singleton/sound_effect/robot
+ if(/datum/singleton/sound_effect/radio)
+ if(TTS_TRAIT_ROBOTIZE in traits)
+ return /datum/singleton/sound_effect/radio_robot
+ if(/datum/singleton/sound_effect/megaphone)
+ if(TTS_TRAIT_ROBOTIZE in traits)
+ return /datum/singleton/sound_effect/megaphone_robot
+ return .
+
+/datum/component/tts_component/proc/cast_tts(atom/speaker, mob/listener, message, atom/location, is_local = TRUE, effect = null, traits = TTS_TRAIT_RATE_FASTER, preSFX, postSFX)
+ SIGNAL_HANDLER
+
+ if(!message)
+ return
+ var/datum/preferences/prefs = listener?.client?.prefs
+ if(prefs?.read_preference(/datum/preference/choiced/sound_tts) != TTS_SOUND_ENABLED || prefs?.read_preference(/datum/preference/numeric/sound_tts_volume) == 0)
+ return
+ if(HAS_TRAIT(listener, TRAIT_DEAF))
+ return
+ if(!speaker)
+ speaker = parent
+ if(!location)
+ location = parent
+ if(effect == /datum/singleton/sound_effect/radio)
+ if(listener == speaker && !issilicon(parent)) // don't hear both radio and whisper from yourself
+ return
+
+ effect = get_effect(effect)
+
+ INVOKE_ASYNC(SStts220, TYPE_PROC_REF(/datum/controller/subsystem/tts220, get_tts), location, listener, message, tts_seed, is_local, effect, traits, preSFX, postSFX)
+
+/datum/component/tts_component/proc/tts_trait_add(atom/user, trait)
+ SIGNAL_HANDLER
+
+ if(!isnull(trait) && !(trait in traits))
+ traits += trait
+
+/datum/component/tts_component/proc/tts_trait_remove(atom/user, trait)
+ SIGNAL_HANDLER
+
+ if(!isnull(trait) && (trait in traits))
+ traits -= trait
+
+// Component usage
+
+/mob/living/silicon/verb/synth_change_voice()
+ set name = "Смена голоса"
+ set desc = "Express yourself!"
+ set category = "Silicon Commands"
+ change_tts_seed(src, new_traits = list(TTS_TRAIT_ROBOTIZE))
diff --git a/modular_bandastation/tts/code/tts_configuration.dm b/modular_bandastation/tts/code/tts_configuration.dm
index 7f8d628e23674..5d199f9ccc0ef 100644
--- a/modular_bandastation/tts/code/tts_configuration.dm
+++ b/modular_bandastation/tts/code/tts_configuration.dm
@@ -6,9 +6,14 @@
default = ""
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
-/datum/config_entry/flag/tts_cache
+/datum/config_entry/flag/tts_cache_enabled
default = FALSE
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
/datum/config_entry/string/ffmpeg_cpuaffinity
+ default = ""
+ protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
+
+/datum/config_entry/string/tts_api_url_silero
+ default = ""
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
diff --git a/modular_bandastation/tts/code/tts_mob_Hear.dm b/modular_bandastation/tts/code/tts_mob_Hear.dm
deleted file mode 100644
index ded3d492a8457..0000000000000
--- a/modular_bandastation/tts/code/tts_mob_Hear.dm
+++ /dev/null
@@ -1,67 +0,0 @@
-/mob/proc/Hear_tts(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods, message_range)
- if(!SStts220.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/message_tts = translate_language(language = message_language, raw_message = raw_message)
-
- INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(tts_cast), speaker, src, message_tts, real_speaker.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_bandastation/tts/code/tts_preferences.dm b/modular_bandastation/tts/code/tts_preferences.dm
index bfcd0a61d8c9c..e747d7a18b1f3 100644
--- a/modular_bandastation/tts/code/tts_preferences.dm
+++ b/modular_bandastation/tts/code/tts_preferences.dm
@@ -1,8 +1,6 @@
/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 SStts220.tts_providers)
var/datum/tts_provider/provider = SStts220.tts_providers[_provider]
@@ -21,53 +19,37 @@
"category" = seed.category,
"gender" = seed.gender,
"provider" = initial(seed.provider.name),
- "donator_level" = seed.donator_level,
+ "donator_level" = seed.required_donator_level,
))
data["seeds"] = seeds
-
data["phrases"] = TTS_PHRASES
-
return data
+/datum/preferences/ui_data(mob/user)
+ var/list/data = ..()
+ data["tts_seed"] = read_preference(/datum/preference/text/tts_seed)
+ return data
/datum/preferences/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
- if (.)
+ if(.)
return
-
- switch (action)
+ switch(action)
if("listen")
var/phrase = params["phrase"]
var/seed_name = params["seed"]
-
if((phrase in TTS_PHRASES) && (seed_name in SStts220.tts_seeds))
- INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(tts_cast), null, usr, phrase, seed_name, FALSE)
+ INVOKE_ASYNC(SStts220, TYPE_PROC_REF(/datum/controller/subsystem/tts220, get_tts), null, usr, phrase, SStts220.tts_seeds[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)
+ if(!isnull(seed_name) && (seed_name in SStts220.tts_seeds))
+ write_preference(GLOB.preference_entries[/datum/preference/text/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/text/tts_seed
+ savefile_key = "tts_seed"
+ savefile_identifier = PREFERENCE_CHARACTER
-/datum/preference/numeric/sound_tts_radio/create_default_value()
- return 50
+/datum/preference/text/tts_seed/apply_to_human(mob/living/carbon/human/target, value)
+ target.AddComponent(/datum/component/tts_component, SStts220.tts_seeds[value])
diff --git a/modular_bandastation/tts/code/tts_provider.dm b/modular_bandastation/tts/code/tts_provider.dm
index aa159eef07cde..65d2e484fdbc3 100644
--- a/modular_bandastation/tts/code/tts_provider.dm
+++ b/modular_bandastation/tts/code/tts_provider.dm
@@ -1,18 +1,19 @@
/datum/tts_provider
var/name = "STUB"
var/is_enabled = TRUE
+ var/api_url
- // Throttling
var/is_throttled = FALSE
var/throttled_until = 0
+ var/timed_out_requests = 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)
+/datum/tts_provider/proc/process_response(list/response)
return null
/datum/tts_provider/proc/throttle_check()
diff --git a/modular_bandastation/tts/code/tts_seed.dm b/modular_bandastation/tts/code/tts_seed.dm
index 627dd3f35f615..23c005e0a660b 100644
--- a/modular_bandastation/tts/code/tts_seed.dm
+++ b/modular_bandastation/tts/code/tts_seed.dm
@@ -1,24 +1,42 @@
-/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 movable atom
-/atom/movable
- var/tts_seed
-
-/datum/preference/text/tts_seed/apply_to_human(mob/living/carbon/human/target, value)
- target.tts_seed = value
+/datum/dna
+ var/datum/tts_seed/tts_seed_dna
+
+/datum/dna/transfer_identity(mob/living/carbon/destination, transfer_SE, transfer_species)
+ if(!istype(destination))
+ return
+ . = ..()
+ destination.dna.tts_seed_dna = tts_seed_dna
+ destination.AddComponent(/datum/component/tts_component, tts_seed_dna)
+
+/datum/dna/copy_dna(datum/dna/new_dna)
+ . = ..()
+ new_dna.tts_seed_dna = tts_seed_dna
+
+/atom/proc/add_tts_component()
+ return
+
+/atom/Initialize(mapload, ...)
+ . = ..()
+ add_tts_component()
+
+/atom/proc/cast_tts(mob/listener, message, atom/location, is_local = TRUE, effect = null, traits = TTS_TRAIT_RATE_FASTER, preSFX, postSFX)
+ SEND_SIGNAL(src, COMSIG_ATOM_TTS_CAST, listener, message, location, is_local, effect, traits, preSFX, postSFX)
+
+// TODO: Do it better?
+/atom/proc/get_tts_seed()
+ var/datum/component/tts_component/tts_component = GetComponent(/datum/component/tts_component)
+ if(tts_component)
+ return tts_component.tts_seed
+
+/atom/proc/change_tts_seed(mob/chooser, override, list/new_traits = null)
+ if(!get_tts_seed())
+ if(alert(chooser, "Отсутствует TTS компонент. Создать?", "Изменение TTS", "Да", "Нет") == "Нет")
+ return
+ AddComponent(/datum/component/tts_component, /datum/tts_seed/silero/angel)
+ SEND_SIGNAL(src, COMSIG_ATOM_TTS_SEED_CHANGE, chooser, override, new_traits)
+
+/atom/proc/tts_trait_add(trait)
+ SEND_SIGNAL(src, COMSIG_ATOM_TTS_TRAIT_ADD, trait)
+
+/atom/proc/tts_trait_remove(trait)
+ SEND_SIGNAL(src, COMSIG_ATOM_TTS_TRAIT_REMOVE, trait)
diff --git a/modular_bandastation/tts/code/tts_sound.dm b/modular_bandastation/tts/code/tts_sound.dm
deleted file mode 100644
index f9271e3f399cc..0000000000000
--- a/modular_bandastation/tts/code/tts_sound.dm
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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(CONFIG_GET(string/ffmpeg_cpuaffinity))
- taskset = "taskset -ac [CONFIG_GET(string/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_bandastation/tts/code/tts_sound_TEMPORARY.dm b/modular_bandastation/tts/code/tts_sound_TEMPORARY.dm
deleted file mode 100644
index a8bae493691ec..0000000000000
--- a/modular_bandastation/tts/code/tts_sound_TEMPORARY.dm
+++ /dev/null
@@ -1,77 +0,0 @@
-// 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_bandastation/tts/code/tts_subsystem.dm b/modular_bandastation/tts/code/tts_subsystem.dm
index 2eb40ae067265..df429adbe378e 100644
--- a/modular_bandastation/tts/code/tts_subsystem.dm
+++ b/modular_bandastation/tts/code/tts_subsystem.dm
@@ -1,161 +1,93 @@
+#define TTS_REPLACEMENTS_FILE_PATH "config/bandastation/tts_replacements.json"
+#define TTS_ACRONYM_REPLACEMENTS "tts_acronym_replacements"
+#define TTS_JOB_REPLACEMENTS "tts_job_replacements"
+
+#define FILE_CLEANUP_DELAY 30 SECONDS
+
SUBSYSTEM_DEF(tts220)
name = "Text-to-Speech 220"
init_order = INIT_ORDER_DEFAULT
- wait = 1 SECONDS
+ wait = 0.5 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 = ""
+ /// All time tts uses
+ VAR_PRIVATE/tts_wanted = 0
+ /// Amount of errored requests to providers
+ VAR_PRIVATE/tts_request_failed = 0
+ /// Amount of successfull requests to providers
+ VAR_PRIVATE/tts_request_succeeded = 0
+ /// Amount of cache hits
+ VAR_PRIVATE/tts_reused = 0
+ /// Assoc list of request error codes
+ VAR_PRIVATE/list/tts_errors = list()
+ /// Last errored requests' contents
+ VAR_PRIVATE/tts_error_raw = ""
// Simple Moving Average RPS
- var/list/tts_rps_list = list()
- var/tts_sma_rps = 0
+ VAR_PRIVATE/list/tts_rps_list = list()
+ VAR_PRIVATE/tts_sma_rps = 0
- // Requests per Second (RPS), only real API requests
- var/tts_rps = 0
- var/tts_rps_counter = 0
+ /// Requests per Second (RPS), only real API requests
+ VAR_PRIVATE/tts_rps = 0
+ VAR_PRIVATE/tts_rps_counter = 0
- // Total Requests per Second (TRPS), all TTS request, even reused
- var/tts_trps = 0
- var/tts_trps_counter = 0
+ /// Total Requests per Second (TRPS), all TTS request, even reused
+ VAR_PRIVATE/tts_trps = 0
+ VAR_PRIVATE/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
+ /// Reused Requests per Second (RRPS), only reused requests
+ VAR_PRIVATE/tts_rrps = 0
+ VAR_PRIVATE/tts_rrps_counter = 0
+ VAR_PRIVATE/is_enabled = TRUE
+ /// List of all available TTS seeds
var/list/datum/tts_seed/tts_seeds = list()
- var/list/tts_seeds_names = list()
- var/list/tts_seeds_names_by_donator_levels = list()
+ /// List of all available TTS providers
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" = "посетитель",
+ VAR_PRIVATE/tts_requests_queue_limit = 100
+ VAR_PRIVATE/tts_rps_limit = 11
+ VAR_PRIVATE/last_network_fire = 0
+
+ /// General request queue
+ VAR_PRIVATE/list/tts_queue = list()
+ /// Ffmpeg queue. Is an assoc list. Each entry is a filename mapped to the list of sound processing requests which require it.
+ VAR_PRIVATE/list/tts_effects_queue = list()
+ /// Lazy list of request that need to performed to TTS provider API
+ VAR_PRIVATE/list/tts_requests_queue
+
+ /// List of currently existing binding of atom and sound channel: `atom` => `sound_channel`. SS220 TODO: free channel when atom is detroyed and may be on some other circumstances
+ VAR_PRIVATE/list/tts_local_channels_by_owner = list()
+
+ /// Mapping of BYOND gender to TTS gender
+ VAR_PRIVATE/list/gender_table = list(
+ NEUTER = TTS_GENDER_ANY,
+ PLURAL = TTS_GENDER_ANY,
+ MALE = TTS_GENDER_MALE,
+ FEMALE = TTS_GENDER_FEMALE
)
-
+ /// Is debug mode enabled or not. Information about `sanitized_messages_cache_hit` and `sanitized_messages_cache_miss` is printed to debug logs each SS fire
+ VAR_PRIVATE/debug_mode_enabled = FALSE
+ /// Whether or not caching of sanitized messages is performed
+ VAR_PRIVATE/sanitized_messages_caching = TRUE
+ /// Amount of message duplicates that were sanitized current SS fire. Debug purpose only
+ VAR_PRIVATE/sanitized_messages_cache_hit = 0
+ /// Amount of unique messages that were sanitized current SS fire. Debug purpose only
+ VAR_PRIVATE/sanitized_messages_cache_miss = 0
+ /// List of all messages that were sanitized as: `meesage md5 hash` => `message`
+ VAR_PRIVATE/list/sanitized_messages_cache = list()
+
+ /// List of all available TTS seed names
+ VAR_PRIVATE/list/tts_seeds_names = list()
+ /// List of all available TTS seed names, mapped by donator level for faster access
+ VAR_PRIVATE/list/tts_seeds_names_by_donator_levels = list()
+
+ /// List of all tts seeds mapped by TTS gender: `tts gender` => `list of seeds`
+ VAR_PRIVATE/list/tts_seeds_by_gender
+ /// Replacement map for acronyms for proper TTS spelling. Not private because `replacetext` can use only global procs
+ var/list/tts_acronym_replacements
+ /// Replacement map for jobs for proper TTS spelling
+ VAR_PRIVATE/list/tts_job_replacements
/datum/controller/subsystem/tts220/stat_entry(msg)
msg += "tRPS:[tts_trps] "
msg += "rRPS:[tts_rrps] "
@@ -172,6 +104,7 @@ SUBSYSTEM_DEF(tts220)
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")
@@ -179,17 +112,31 @@ SUBSYSTEM_DEF(tts220)
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)
+ tts_seeds_names_by_donator_levels["[seed.required_donator_level]"] += list(seed.name)
+ LAZYADDASSOCLIST(tts_seeds_by_gender, seed.gender, seed.name)
+ tts_seeds_names = sortTim(tts_seeds_names, GLOBAL_PROC_REF(cmp_text_asc))
/datum/controller/subsystem/tts220/Initialize(start_timeofday)
- is_enabled = CONFIG_GET(flag/tts_enabled)
- if(!is_enabled)
- flags |= SS_NO_FIRE
+ if(!CONFIG_GET(flag/tts_enabled))
+ is_enabled = FALSE
+ return SS_INIT_NO_NEED
+
+ load_replacements()
return SS_INIT_SUCCESS
+/datum/controller/subsystem/tts220/pause()
+ . = ..()
+ is_enabled = FALSE
+
/datum/controller/subsystem/tts220/fire()
+ if(last_network_fire + 1 SECONDS <= world.time)
+ fire_networking()
+ fire_sound_processing()
+
+/datum/controller/subsystem/tts220/proc/fire_networking()
+ last_network_fire = world.time
+
tts_rps = tts_rps_counter
tts_rps_counter = 0
tts_trps = tts_trps_counter
@@ -198,16 +145,16 @@ SUBSYSTEM_DEF(tts220)
tts_rrps_counter = 0
tts_rps_list += tts_rps
- if(tts_rps_list.len > 15)
+ if(length(tts_rps_list) > 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)
+ tts_sma_rps = round(rps_sum / length(tts_rps_list), 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)
+ var/requests = LAZYCOPY_RANGE(tts_requests_queue, 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]
@@ -215,26 +162,63 @@ SUBSYSTEM_DEF(tts220)
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)
+ LAZYCUT(tts_requests_queue, 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]"
+ logger.Log(LOG_CATEGORY_DEBUG, "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/tts220/proc/fire_sound_processing()
+ var/queue_position = 1
+ while(LAZYLEN(tts_effects_queue) >= queue_position)
+ var/filename = tts_effects_queue[queue_position++]
+ INVOKE_ASYNC(src, PROC_REF(process_filename_sound_effect_requests), filename)
+
+ if(MC_TICK_CHECK)
+ break
+
+ LAZYCUT(tts_effects_queue, 1, queue_position)
+
+/datum/controller/subsystem/tts220/proc/process_filename_sound_effect_requests(filename)
+ var/list/filename_requests = tts_effects_queue[filename]
+ var/datum/sound_effect_request/request = filename_requests[1]
+
+ if(!apply_sound_effect(request.effect, request.original_filename, request.output_filename))
+ return
+
+ for(var/datum/sound_effect_request/adjacent_request as anything in filename_requests)
+ adjacent_request.cb.InvokeAsync()
+
/datum/controller/subsystem/tts220/Recover()
is_enabled = SStts220.is_enabled
tts_wanted = SStts220.tts_wanted
tts_request_failed = SStts220.tts_request_failed
tts_request_succeeded = SStts220.tts_request_succeeded
tts_reused = SStts220.tts_reused
+ tts_acronym_replacements = SStts220.tts_acronym_replacements
+ tts_job_replacements = SStts220.tts_job_replacements
+
+/datum/controller/subsystem/tts220/proc/load_replacements()
+ if(!fexists(TTS_REPLACEMENTS_FILE_PATH))
+ logger.Log(LOG_CATEGORY_DEBUG, "No file for TTS replacements located at: [TTS_REPLACEMENTS_FILE_PATH]. No replacements will be applied for TTS.")
+ return
+
+ var/tts_replacements_json = file2text(TTS_REPLACEMENTS_FILE_PATH)
+ if(!length(tts_replacements_json))
+ logger.Log(LOG_CATEGORY_DEBUG, "TTS replacements file is empty at: [TTS_REPLACEMENTS_FILE_PATH].")
+ return
+
+ var/list/replacements = json_decode(tts_replacements_json)
+ tts_acronym_replacements = replacements[TTS_ACRONYM_REPLACEMENTS]
+ tts_job_replacements = replacements[TTS_JOB_REPLACEMENTS]
/datum/controller/subsystem/tts220/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 принудительно отключена!"))
+ to_chat(world, span_info("SERVER: очередь запросов превысила лимит, подсистема [src] принудительно отключена!"))
return FALSE
if(tts_rps_counter < tts_rps_limit)
@@ -243,24 +227,25 @@ SUBSYSTEM_DEF(tts220)
tts_rps_counter++
return TRUE
- tts_requests_queue += list(list(text, seed, proc_callback))
+ LAZYADD(tts_requests_queue, list(list(text, seed, proc_callback)))
return TRUE
-/datum/controller/subsystem/tts220/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)
+/datum/controller/subsystem/tts220/proc/get_tts(atom/speaker, mob/listener, message, datum/tts_seed/tts_seed, is_local = TRUE, datum/singleton/sound_effect/effect = null, 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))
+ if(ispath(tts_seed) && SStts220.tts_seeds[initial(tts_seed.name)])
+ tts_seed = SStts220.tts_seeds[initial(tts_seed.name)]
+ if(!istype(tts_seed))
return
- var/datum/tts_seed/seed = tts_seeds[seed_name]
tts_wanted++
tts_trps_counter++
- var/datum/tts_provider/provider = seed.provider
+ var/datum/tts_provider/provider = tts_seed.provider
if(!provider.is_enabled)
return
if(provider.throttle_check())
@@ -281,25 +266,27 @@ SUBSYSTEM_DEF(tts220)
if(traits & TTS_TRAIT_PITCH_WHISPER)
text = provider.pitch_whisper(text)
- var/hash = rustgss220_hash_string(RUSTG_HASH_MD5, text)
- var/filename = "sound/tts_cache/[seed.name]/[hash]"
+ var/hash = md5(lowertext(text))
- var/datum/callback/play_tts_cb = CALLBACK(src, PROC_REF(play_tts), speaker, listener, filename, is_local, effect, preSFX, postSFX)
+ var/filename = "data/tts_cache/[tts_seed.name]/[hash]"
+ var/datum/singleton/sound_effect/effect_singleton = GET_SINGLETON(effect)
if(fexists("[filename].ogg"))
tts_reused++
tts_rrps_counter++
- play_tts(speaker, listener, filename, is_local, effect, preSFX, postSFX)
+ play_tts(speaker, listener, filename, is_local, effect_singleton, preSFX, postSFX)
return
+ var/datum/callback/play_tts_cb = CALLBACK(src, PROC_REF(play_tts), speaker, listener, filename, is_local, effect_singleton, preSFX, postSFX)
+
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)
+ queue_request(text, tts_seed, CALLBACK(src, PROC_REF(get_tts_callback), speaker, listener, filename, tts_seed, is_local, effect_singleton, preSFX, postSFX))
+
LAZYADD(tts_queue[filename], play_tts_cb)
/datum/controller/subsystem/tts220/proc/get_tts_callback(atom/speaker, mob/listener, filename, datum/tts_seed/seed, is_local, effect, preSFX, postSFX, datum/http_response/response)
@@ -307,17 +294,15 @@ SUBSYSTEM_DEF(tts220)
// 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.")
+ provider.timed_out_requests++
+ log_game(span_warning("Error connecting to [provider.name] TTS API. Please inform a maintainer or server host."))
+ message_admins(span_warning("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])")
+ log_game(span_warning("Error performing [provider.name] TTS API request (Code: [response.status_code])"))
+ message_admins(span_warning("Error performing [provider.name] TTS API request (Code: [response.status_code])"))
tts_request_failed++
if(response.status_code)
if(tts_errors["[response.status_code]"])
@@ -336,8 +321,8 @@ SUBSYSTEM_DEF(tts220)
rustgss220_file_write_b64decode(voice, "[filename].ogg")
- if (!CONFIG_GET(flag/tts_cache))
- addtimer(CALLBACK(src, PROC_REF(cleanup_tts_file), "[filename].ogg"), 30 SECONDS)
+ if(!CONFIG_GET(flag/tts_cache_enabled))
+ addtimer(CALLBACK(src, PROC_REF(cleanup_tts_file), "[filename].ogg"), FILE_CLEANUP_DELAY)
for(var/datum/callback/cb in tts_queue[filename])
cb.InvokeAsync()
@@ -345,99 +330,71 @@ SUBSYSTEM_DEF(tts220)
tts_queue -= filename
-/datum/controller/subsystem/tts220/proc/play_tts(atom/speaker, mob/listener, filename, is_local = TRUE, effect = SOUND_EFFECT_NONE, preSFX = null, postSFX = null)
+/datum/controller/subsystem/tts220/proc/queue_sound_effect_processing(pure_filename, effect, processed_filename, datum/callback/output_tts_cb)
+ var/datum/sound_effect_request/request = new
+ request.original_filename = "[pure_filename].ogg"
+ request.output_filename = processed_filename
+ request.effect = effect
+ request.cb = output_tts_cb
+ LAZYADD(tts_effects_queue[processed_filename], request)
+
+/datum/controller/subsystem/tts220/proc/play_tts(atom/speaker, mob/listener, pure_filename, is_local = TRUE, datum/singleton/sound_effect/effect = null, 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/filename2play = "[pure_filename][effect?.suffix].ogg"
- var/turf/turf_source = get_turf(speaker)
+ if(isnull(effect) || fexists(filename2play))
+ output_tts(speaker, listener, filename2play, is_local, preSFX, postSFX)
+ return
- 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/datum/callback/output_tts_cb = CALLBACK(src, PROC_REF(output_tts), speaker, listener, filename2play, is_local, preSFX, postSFX)
+ queue_sound_effect_processing(pure_filename, effect, filename2play, output_tts_cb)
- var/sound/output = sound(voice)
- output.status = SOUND_STREAM
+/datum/controller/subsystem/tts220/proc/output_tts(atom/speaker, mob/listener, filename2play, is_local = TRUE, preSFX = null, postSFX = null)
+ var/volume = listener?.client?.prefs?.read_preference(/datum/preference/numeric/sound_tts_volume)
+ if(!volume)
+ return
- if(isnull(speaker))
+ var/turf/turf_source = get_turf(speaker)
+
+ var/sound/output = sound(filename2play)
+ output.status = SOUND_STREAM
+ if(!is_local || 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
+ output.volume = volume * 0.75 // non-local is slightly less loud // TODO220: Make volume different
+ output.environment = SOUND_ENVIRONMENT_NONE
if(output.volume <= 0)
return
- if(preSFX)
- play_sfx(listener, preSFX, output.channel, output.volume, output.environment)
-
+ play_sfx_if_exists(listener, preSFX, output)
SEND_SOUND(listener, output)
+ play_sfx_if_exists(listener, postSFX, output)
+
return
- if(preSFX)
- play_sfx(listener, preSFX, output.channel, output.volume, output.environment)
+ play_sfx_if_exists(listener, preSFX, output)
- listener.playsound_local(turf_source, output, volume, sound_to_use = output, channel = channel, wait = TRUE)
+ output = listener.playsound_local(turf_source, output, volume)
if(!output || output.volume <= 0)
return
- if(postSFX)
- play_sfx(listener, postSFX, output.channel, output.volume, output.environment)
+ play_sfx_if_exists(listener, postSFX, output)
+
+/datum/controller/subsystem/tts220/proc/play_sfx_if_exists(mob/listener, sfx, sound/output)
+ if(sfx)
+ play_sfx(listener, sfx, output.volume, output.environment)
-/datum/controller/subsystem/tts220/proc/play_sfx(mob/listener, sfx, channel, volume, environment)
+/datum/controller/subsystem/tts220/proc/play_sfx(mob/listener, sfx, 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/tts220/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/tts220/proc/cleanup_tts_file(filename)
fdel(filename)
@@ -453,10 +410,6 @@ SUBSYSTEM_DEF(tts220)
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/tts220/proc/get_random_seed(owner)
@@ -465,113 +418,73 @@ SUBSYSTEM_DEF(tts220)
/datum/controller/subsystem/tts220/proc/sanitize_tts_input(message)
var/hash
if(sanitized_messages_caching)
- hash = rustgss220_hash_string(RUSTG_HASH_MD5, message)
+ hash = md5(lowertext(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/acronyms = new(@"(? {
const { act, data } = useBackend();
- const {
- providers,
- seeds,
- phrases,
- character_preferences: {
- misc: { tts_seed },
- },
- } = data;
+ const { providers, seeds, phrases, tts_seed } = data;
const donator_level = 5;
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts
index b8867f0878d21..2a6e6c3cfc72d 100644
--- a/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts
@@ -147,7 +147,6 @@ export type PreferencesMenuData = {
gender: Gender;
joblessrole: JoblessRole;
species: string;
- tts_seed: string; // BANDASTATION EDIT ADD - TTS
};
randomization: Record;
@@ -177,7 +176,10 @@ export type PreferencesMenuData = {
active_slot: number;
name_to_use: string;
+ window: Window;
+
// BANDASTATION EDIT START - TTS
+ tts_seed: string;
tts_enabled: BooleanLike;
providers: Array<{
name: string;
@@ -193,8 +195,6 @@ export type PreferencesMenuData = {
}>;
phrases: string[];
// BANDASTATION EDIT END
-
- window: Window;
};
export type ServerData = {
diff --git a/tools/ci/install_rust_g.sh b/tools/ci/install_rust_g.sh
index c237162d8faa2..582e80536f5d0 100755
--- a/tools/ci/install_rust_g.sh
+++ b/tools/ci/install_rust_g.sh
@@ -7,3 +7,7 @@ mkdir -p ~/.byond/bin
wget -nv -O ~/.byond/bin/librust_g.so "https://github.com/tgstation/rust-g/releases/download/$RUST_G_VERSION/librust_g.so"
chmod +x ~/.byond/bin/librust_g.so
ldd ~/.byond/bin/librust_g.so
+
+wget -nv -O ~/.byond/bin/librust_g_ss220.so "https://github.com/ss220club/rust-g-tg/releases/download/$RUST_G_VERSION_SS220/librust_g.so"
+chmod +x ~/.byond/bin/librust_g_ss220.so
+ldd ~/.byond/bin/librust_g_ss220.so
diff --git a/tools/tgs_scripts/InstallDeps.sh b/tools/tgs_scripts/InstallDeps.sh
index e66053ab89c7c..cc38087096cda 100755
--- a/tools/tgs_scripts/InstallDeps.sh
+++ b/tools/tgs_scripts/InstallDeps.sh
@@ -8,20 +8,21 @@ has_cargo="$(command -v ~/.cargo/bin/cargo)"
has_sudo="$(command -v sudo)"
has_youtubedl="$(command -v youtube-dl)"
has_pip3="$(command -v pip3)"
+has_cmake="$(command -v cmake)"
set -e
set -x
# apt packages, libssl needed by rust-g but not included in TGS barebones install
-if ! ( [ -x "$has_git" ] && [ -x "$has_curl" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then
+if ! ( [ -x "$has_git" ] && [ -x "$has_curl" ] && [ -x "$has_cmake" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then
echo "Installing apt dependencies..."
if ! [ -x "$has_sudo" ]; then
dpkg --add-architecture i386
apt-get update
- apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl
+ apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl cmake
else
sudo dpkg --add-architecture i386
sudo apt-get update
- sudo apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl
+ sudo apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl cmake
fi
fi
diff --git a/tools/tgs_scripts/PreCompile.sh b/tools/tgs_scripts/PreCompile.sh
index ae8cba7a45b96..b33f821942e54 100755
--- a/tools/tgs_scripts/PreCompile.sh
+++ b/tools/tgs_scripts/PreCompile.sh
@@ -32,6 +32,25 @@ env PKG_CONFIG_ALLOW_CROSS=1 ~/.cargo/bin/cargo build --ignore-rust-version --re
mv target/i686-unknown-linux-gnu/release/librust_g.so "$1/librust_g.so"
cd ..
+# update rust-g-tg s220
+if [ ! -d "rust-g-tg" ]; then
+ echo "Cloning rust-g ss220..."
+ git clone https://github.com/ss220club/rust-g-tg
+ cd rust-g-tg
+ ~/.cargo/bin/rustup target add i686-unknown-linux-gnu
+else
+ echo "Fetching rust-g ss220..."
+ cd rust-g-tg
+ git fetch
+ ~/.cargo/bin/rustup target add i686-unknown-linux-gnu
+fi
+
+echo "Deploying rust-g ss220..."
+git checkout master
+env PKG_CONFIG_ALLOW_CROSS=1 ~/.cargo/bin/cargo build --ignore-rust-version --release --target=i686-unknown-linux-gnu
+mv target/i686-unknown-linux-gnu/release/librust_g.so "$1/librust_g_ss220.so"
+cd ..
+
# compile tgui
echo "Compiling tgui..."
cd "$1"