diff --git a/SpeechMod/Settings.cs b/SpeechMod/Settings.cs index d198182..b1756f1 100644 --- a/SpeechMod/Settings.cs +++ b/SpeechMod/Settings.cs @@ -6,6 +6,8 @@ public class Settings : UnityModManager.ModSettings { public string[] AvailableVoices; + public bool UseBracketNarratorVoice = true; + public int NarratorVoice = 0; public int NarratorRate = 0; public int NarratorVolume = 100; diff --git a/SpeechMod/Unity/MenuGUI.cs b/SpeechMod/Unity/MenuGUI.cs index 212c630..681f1f0 100644 --- a/SpeechMod/Unity/MenuGUI.cs +++ b/SpeechMod/Unity/MenuGUI.cs @@ -16,6 +16,13 @@ public static void OnGui() { AddVoiceSelector("Narrator Voice - See nationality below", ref Main.Settings.NarratorVoice, ref m_NarratorPreviewText, ref Main.Settings.NarratorRate, ref Main.Settings.NarratorVolume, ref Main.Settings.NarratorPitch, VoiceType.Narrator); + GUILayout.BeginVertical("", GUI.skin.box); + GUILayout.BeginHorizontal(); + GUILayout.Label("Use Narrator voice for text in brackets [ ]", GUILayout.ExpandWidth(false)); + Main.Settings.UseBracketNarratorVoice = GUILayout.Toggle(Main.Settings.UseBracketNarratorVoice, "Enabled"); + GUILayout.EndHorizontal(); + GUILayout.EndVertical(); + GUILayout.BeginVertical("", GUI.skin.box); GUILayout.BeginHorizontal(); diff --git a/SpeechMod/Voice/WindowsSpeech.cs b/SpeechMod/Voice/WindowsSpeech.cs index 4601112..2ed1f1b 100644 --- a/SpeechMod/Voice/WindowsSpeech.cs +++ b/SpeechMod/Voice/WindowsSpeech.cs @@ -5,6 +5,7 @@ using Kingmaker.Blueprints; using Kingmaker.UnitLogic.Abilities.Components.TargetCheckers; using SpeechMod.Unity; +using System.Text; #if DEBUG using System.Reflection; @@ -68,8 +69,61 @@ public static int Length(string text) return arr.Aggregate(text, (current, t) => current.Replace(t, "")).Length; } + private string GetVoiceStartTag(VoiceType voiceType) + { + return voiceType switch + { + VoiceType.Narrator => CombinedNarratorVoiceStart, + VoiceType.Female => CombinedFemaleVoiceStart, + VoiceType.Male => CombinedMaleVoiceStart, + VoiceType.Protagonist => CombinedProtagonistVoiceStart, + _ => CombinedDialogVoiceStart // Fallback + }; + } + + // Process text with brackets to switch voices + private string ProcessBrackets(string text, VoiceType? voiceType = null) + { + if (!Main.Settings.UseBracketNarratorVoice || string.IsNullOrEmpty(text) || !text.Contains("[")) + { + return text; + } + + // Determine what voice to switch back to after the ']' + string returnVoiceTag = voiceType.HasValue ? GetVoiceStartTag(voiceType.Value) : CombinedDialogVoiceStart; + + StringBuilder sb = new(); + int depth = 0; + + // Iterate through each character instead of using regex to handle nested brackets as regex would struggle with nested structures + for (int i = 0; i < text.Length; i++) + { + char c = text[i]; + if (c == '[') + { + if (depth == 0) sb.Append($"{CombinedNarratorVoiceStart}"); + depth++; + } + else if (c == ']') + { + if (depth > 0) + { + depth--; + if (depth == 0) sb.Append($"{returnVoiceTag}"); + } + } + else + { + sb.Append(c); + } + } + return sb.ToString(); + } + private string FormatGenderSpecificVoices(string text) { + text = ProcessBrackets(text); + text = text.Replace("", $"{CombinedNarratorVoiceStart}"); text = text.Replace("", $"{CombinedDialogVoiceStart}"); @@ -195,6 +249,8 @@ public void SpeakAs(string text, VoiceType voiceType, float delay = 0) return; } + text = ProcessBrackets(text, voiceType); + if (Main.Settings!.UseProtagonistSpecificVoice && voiceType == VoiceType.Protagonist) { text = $"{CombinedProtagonistVoiceStart}{text}";