stardew-access/stardew-access/Patches/DialogueBoxPatch.cs

132 lines
4.5 KiB
C#

using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI;
using StardewValley;
using StardewValley.Menus;
namespace stardew_access.Patches
{
internal class DialoguePatches
{
private static string currentDialogue = "";
private static string previousSpeakerName = "";
private static bool isDialogueAppearingFirstTime = true;
internal static void DialoguePatch(DialogueBox __instance, SpriteBatch b)
{
try
{
if (__instance.transitioning) return;
if (narrateCharacterDialogue(__instance)) return;
if (narrateQuestionDialogue(__instance)) return;
narrateBasicDialogue(__instance.getCurrentString());
}
catch (Exception e)
{
MainClass.ErrorLog($"Unable to narrate dialog:\n{e.StackTrace}\n{e.Message}");
}
}
internal static void RecieveLeftClickPatch()
{
// CLears the currentDialogue string on closing dialog
Cleanup();
}
private static bool narrateCharacterDialogue(DialogueBox __instance)
{
if (__instance.characterDialogue == null) return false;
// For Normal Character dialogues
Dialogue dialogue = __instance.characterDialogue;
string speakerName = dialogue.speaker.displayName;
string dialogueText = "";
string responseText = "";
bool hasResponses = dialogue.isCurrentDialogueAQuestion();
dialogueText = $"{speakerName} said {__instance.getCurrentString()}";
if (hasResponses)
{
responseText = getCurrentResponseText(__instance);
CheckAndSpeak(isDialogueAppearingFirstTime ? $"{dialogueText} \n\t {responseText}" : responseText, responseText);
if (isDialogueAppearingFirstTime) isDialogueAppearingFirstTime = false;
}
else
{
CheckAndSpeak(dialogueText);
}
return true;
}
private static bool narrateQuestionDialogue(DialogueBox __instance)
{
if (!__instance.isQuestion) return false;
// For Dialogues with responses/answers like the dialogue when we click on tv
string questionText = "";
string responseText = "";
bool hasResponses = false;
if (__instance.responses.Count > 0) hasResponses = true;
if (!hasResponses) return false;
questionText = __instance.getCurrentString();
responseText = getCurrentResponseText(__instance);
CheckAndSpeak(isDialogueAppearingFirstTime ? $"{questionText} \n\t {responseText}" : responseText, responseText);
if (isDialogueAppearingFirstTime) isDialogueAppearingFirstTime = false;
return true;
}
private static void narrateBasicDialogue(string dialogue)
{
// Basic dialogues like `No mails in the mail box`
if (Game1.activeClickableMenu is not DialogueBox) return;
CheckAndSpeak(dialogue);
}
private static string getCurrentResponseText(DialogueBox __instance)
{
List<Response> responses = __instance.responses;
if (__instance.selectedResponse >= 0 && __instance.selectedResponse < responses.Count)
{
return $"{__instance.selectedResponse + 1}: {responses[__instance.selectedResponse].responseText}";
}
else
{
// When the dialogue is not finished writing then the selectedResponse is <0 and this results
// in the first response not being detcted, so this sets the first response option to be the default
// if the current dialogue is a question or has responses
return $"1: {responses[0].responseText}";
}
}
private static void CheckAndSpeak(string toSpeak)
{
if (currentDialogue == toSpeak) return;
currentDialogue = toSpeak;
MainClass.ScreenReader.Say(toSpeak, true);
}
private static void CheckAndSpeak(string toSpeak, string checkQuery)
{
if (currentDialogue == checkQuery) return;
currentDialogue = checkQuery;
MainClass.ScreenReader.Say(toSpeak, true);
}
internal static void Cleanup()
{
currentDialogue = "";
isDialogueAppearingFirstTime = true;
}
}
}