diff --git a/stardew-access/HarmonyPatches.cs b/stardew-access/HarmonyPatches.cs index 900e674..78d8c22 100644 --- a/stardew-access/HarmonyPatches.cs +++ b/stardew-access/HarmonyPatches.cs @@ -196,17 +196,17 @@ namespace stardew_access #region Quest Patches harmony.Patch( original: AccessTools.Method(typeof(SpecialOrdersBoard), nameof(SpecialOrdersBoard.draw), new Type[] { typeof(SpriteBatch) }), - postfix: new HarmonyMethod(typeof(QuestPatches), nameof(QuestPatches.SpecialOrdersBoardPatch)) + postfix: new HarmonyMethod(typeof(SpecialOrdersBoardPatch), nameof(SpecialOrdersBoardPatch.DrawPatch)) ); harmony.Patch( original: AccessTools.Method(typeof(QuestLog), nameof(QuestLog.draw), new Type[] { typeof(SpriteBatch) }), - postfix: new HarmonyMethod(typeof(QuestPatches), nameof(QuestPatches.QuestLogPatch)) + postfix: new HarmonyMethod(typeof(QuestLogPatch), nameof(QuestLogPatch.DrawPatch)) ); harmony.Patch( original: AccessTools.Method(typeof(Billboard), nameof(Billboard.draw), new Type[] { typeof(SpriteBatch) }), - postfix: new HarmonyMethod(typeof(QuestPatches), nameof(QuestPatches.BillboardPatch)) + postfix: new HarmonyMethod(typeof(BillboardPatch), nameof(BillboardPatch.DrawPatch)) ); #endregion diff --git a/stardew-access/Patches/IClickableMenuPatch.cs b/stardew-access/Patches/IClickableMenuPatch.cs index 356dbd9..f935345 100644 --- a/stardew-access/Patches/IClickableMenuPatch.cs +++ b/stardew-access/Patches/IClickableMenuPatch.cs @@ -235,7 +235,7 @@ namespace stardew_access.Patches } else if (menu is Billboard) { - QuestPatches.currentDailyQuestText = " "; + BillboardPatch.Cleanup(); } else if (menu is GameMenu) { @@ -284,7 +284,7 @@ namespace stardew_access.Patches } else if (menu is QuestLog) { - QuestPatches.questLogQuery = " "; + QuestLogPatch.Cleaup(); } else if (menu is TailoringMenu) { @@ -314,6 +314,10 @@ namespace stardew_access.Patches { GeodeMenuPatch.Cleanup(); } + else if (menu is SpecialOrdersBoard) + { + SpecialOrdersBoardPatch.Cleanup(); + } InventoryUtils.Cleanup(); TextBoxPatch.activeTextBoxes = ""; diff --git a/stardew-access/Patches/QuestPatches.cs b/stardew-access/Patches/QuestPatches.cs index 0b38787..cbe8441 100644 --- a/stardew-access/Patches/QuestPatches.cs +++ b/stardew-access/Patches/QuestPatches.cs @@ -7,281 +7,5 @@ namespace stardew_access.Patches { internal class QuestPatches { - internal static string currentDailyQuestText = " "; - internal static string questLogQuery = " "; - internal static bool isNarratingQuestInfo = false, firstTimeInIndividualQuest = true; - - #region For Special Orders Board - internal static void SpecialOrdersBoardPatch(SpecialOrdersBoard __instance) - { - try - { - int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position - - if (__instance.acceptLeftQuestButton.visible && __instance.acceptLeftQuestButton.containsPoint(x, y)) - { - string toSpeak = getSpecialOrderDetails(__instance.leftOrder); - - toSpeak = $"Left Quest:\n\t{toSpeak}\n\tPress left click to accept this quest."; - - MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true); - return; - } - - if (__instance.acceptRightQuestButton.visible && __instance.acceptRightQuestButton.containsPoint(x, y)) - { - string toSpeak = getSpecialOrderDetails(__instance.rightOrder); - - toSpeak = $"Right Quest:\n\t{toSpeak}\n\tPress left click to accept this quest."; - - MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true); - return; - } - } - catch (Exception e) - { - MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}"); - } - } - - private static string getSpecialOrderDetails(SpecialOrder order) - { - int daysLeft = order.GetDaysLeft(); - string description = order.GetDescription(); - string objectiveDescription = ""; - string name = order.GetName(); - int moneyReward = order.GetMoneyReward(); - - // Get each objectives - for (int i = 0; i < order.GetObjectiveDescriptions().Count; i++) - { - objectiveDescription += order.GetObjectiveDescriptions()[i] + ", \n"; - } - - string toReturn = $"{name}\n\tDescription:{description}\n\tObjectives: {objectiveDescription}"; - - if (order.IsTimedQuest()) - { - toReturn = $"{toReturn}\n\tTime: {daysLeft} days"; - } - - if (order.HasMoneyReward()) - { - toReturn = $"{toReturn}\n\tReward: {moneyReward}g"; - } - - return toReturn; - } - #endregion - - #region For Normal Billboard in the town - internal static void BillboardPatch(Billboard __instance, bool ___dailyQuestBoard) - { - try - { - if (!___dailyQuestBoard) - { - #region Callender - for (int i = 0; i < __instance.calendarDays.Count; i++) - { - if (__instance.calendarDays[i].containsPoint(Game1.getMouseX(true), Game1.getMouseY(true))) - { - string toSpeak = $"Day {i + 1}"; - - if (__instance.calendarDays[i].name.Length > 0) - { - toSpeak += $", {__instance.calendarDays[i].name}"; - } - if (__instance.calendarDays[i].hoverText.Length > 0) - { - toSpeak += $", {__instance.calendarDays[i].hoverText}"; - } - - if (Game1.dayOfMonth == i + 1) - toSpeak += $", Current"; - - MainClass.ScreenReader.SayWithChecker(toSpeak, true); - } - } - #endregion - } - else - { - #region Daily Quest Board - if (Game1.questOfTheDay == null || Game1.questOfTheDay.currentObjective == null || Game1.questOfTheDay.currentObjective.Length == 0) - { - // No quests - string toSpeak = "No quests for today!"; - if (currentDailyQuestText != toSpeak) - { - currentDailyQuestText = toSpeak; - MainClass.ScreenReader.Say(toSpeak, true); - } - } - else - { - SpriteFont font = ((LocalizedContentManager.CurrentLanguageCode == LocalizedContentManager.LanguageCode.ko) ? Game1.smallFont : Game1.dialogueFont); - string description = Game1.parseText(Game1.questOfTheDay.questDescription, font, 640); - string toSpeak = description; - - if (currentDailyQuestText != toSpeak) - { - currentDailyQuestText = toSpeak; - - // Snap to accept quest button - if (__instance.acceptQuestButton.visible) - { - toSpeak += "\t\n Left click to accept quest."; - __instance.acceptQuestButton.snapMouseCursorToCenter(); - } - - MainClass.ScreenReader.Say(toSpeak, true); - } - } - #endregion - } - } - catch (Exception e) - { - MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}"); - } - } - #endregion - - #region Journal Menu - internal static void QuestLogPatch(QuestLog __instance, int ___questPage, List> ___pages, int ___currentPage, IQuest ____shownQuest, List ____objectiveText) - { - try - { - bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed(); - int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position - string toSpeak = " ", extra = ""; - - if (___questPage == -1) - { - #region Quest Lists - if (!firstTimeInIndividualQuest) - firstTimeInIndividualQuest = true; - - for (int i = 0; i < __instance.questLogButtons.Count; i++) - { - if (___pages.Count() > 0 && ___pages[___currentPage].Count() > i) - { - if (!__instance.questLogButtons[i].containsPoint(x, y)) - continue; - - string name = ___pages[___currentPage][i].GetName(); - int daysLeft = ___pages[___currentPage][i].GetDaysLeft(); - toSpeak = $"{name}"; - - if (daysLeft > 0 && ___pages[___currentPage][i].ShouldDisplayAsComplete()) - toSpeak += $"\t\n {daysLeft} days left"; - - toSpeak += ___pages[___currentPage][i].ShouldDisplayAsComplete() ? " completed!" : ""; - break; - } - } - - if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y)) - toSpeak = "Previous page button"; - else if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y)) - toSpeak = "Next page button"; - else if (__instance.upperRightCloseButton != null && __instance.upperRightCloseButton.visible && __instance.upperRightCloseButton.containsPoint(x, y)) - toSpeak = "Close menu button"; - - if (questLogQuery != toSpeak) - { - questLogQuery = toSpeak; - MainClass.ScreenReader.Say(toSpeak, true); - } - #endregion - } - else - { - #region Individual quest - bool containsReward = __instance.HasReward() || __instance.HasMoneyReward(); - string description = Game1.parseText(____shownQuest.GetDescription(), Game1.dialogueFont, __instance.width - 128); - string title = ____shownQuest.GetName(); - - if (firstTimeInIndividualQuest || (isPrimaryInfoKeyPressed && !isNarratingQuestInfo)) - { - if (firstTimeInIndividualQuest) - toSpeak = "Back button"; - - if (____shownQuest.ShouldDisplayAsComplete()) - { - #region Quest completed menu - - extra = $"Quest: {title} Completed!"; - - if (__instance.HasMoneyReward()) - extra += $"you recieved {____shownQuest.GetMoneyReward()}g"; - - #endregion - } - else - { - #region Quest in-complete menu - extra = $"Title: {title}. \t\n Description: {description}"; - - for (int j = 0; j < ____objectiveText.Count; j++) - { - string parsed_text = Game1.parseText(____objectiveText[j], width: __instance.width - 192, whichFont: Game1.dialogueFont); - if (____shownQuest != null && ____shownQuest is SpecialOrder) - { - OrderObjective order_objective = ((SpecialOrder)____shownQuest).objectives[j]; - if (order_objective.GetMaxCount() > 1 && order_objective.ShouldShowProgress()) - parsed_text += "\n\t" + order_objective.GetCount() + " of " + order_objective.GetMaxCount() + " completed"; - } - - extra += $"\t\nOrder {j + 1}: {parsed_text} \t\n"; - } - - if (____shownQuest != null) - { - int daysLeft = ____shownQuest.GetDaysLeft(); - - if (daysLeft > 0) - extra += $"\t\n{daysLeft} days left."; - } - #endregion - } - - isNarratingQuestInfo = true; - Task.Delay(200).ContinueWith(_ => { isNarratingQuestInfo = false; }); - questLogQuery = " "; - } - - if (!firstTimeInIndividualQuest) - if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y)) - toSpeak = (___currentPage > 0) ? "Previous page button" : "Back button"; - else if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y)) - toSpeak = "Next page button"; - else if (__instance.cancelQuestButton != null && __instance.cancelQuestButton.visible && __instance.cancelQuestButton.containsPoint(x, y)) - toSpeak = "Cancel quest button"; - else if (__instance.upperRightCloseButton != null && __instance.upperRightCloseButton.visible && __instance.upperRightCloseButton.containsPoint(x, y)) - toSpeak = "Close menu button"; - else if (containsReward && __instance.rewardBox.containsPoint(x, y)) - toSpeak = "Left click to collect reward"; - - if (firstTimeInIndividualQuest || (questLogQuery != toSpeak)) - { - questLogQuery = toSpeak; - MainClass.ScreenReader.Say(extra + " \n\t" + toSpeak, true); - - if (firstTimeInIndividualQuest) - firstTimeInIndividualQuest = false; - } - - #endregion - } - } - catch (Exception e) - { - MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}"); - } - } - #endregion - } } diff --git a/stardew-access/Patches/QuestPatches/BillboardPatch.cs b/stardew-access/Patches/QuestPatches/BillboardPatch.cs new file mode 100644 index 0000000..f8e4f47 --- /dev/null +++ b/stardew-access/Patches/QuestPatches/BillboardPatch.cs @@ -0,0 +1,98 @@ +using Microsoft.Xna.Framework.Graphics; +using StardewValley; +using StardewValley.Menus; + +namespace stardew_access.Patches +{ + internal class BillboardPatch + { + private static string billboardQueryKey = ""; + + internal static void DrawPatch(Billboard __instance, bool ___dailyQuestBoard) + { + try + { + if (___dailyQuestBoard) + { + narrateDailyQuestBoard(__instance); + } + else + { + narrateCallendar(__instance); + } + } + catch (Exception e) + { + MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}"); + } + } + + private static void narrateCallendar(Billboard __instance) + { + for (int i = 0; i < __instance.calendarDays.Count; i++) + { + if (!__instance.calendarDays[i].containsPoint(Game1.getMouseX(true), Game1.getMouseY(true))) + continue; + + string toSpeak = $"Day {i + 1}"; + + if (__instance.calendarDays[i].name.Length > 0) + { + toSpeak += $", {__instance.calendarDays[i].name}"; + } + if (__instance.calendarDays[i].hoverText.Length > 0) + { + toSpeak += $", {__instance.calendarDays[i].hoverText}"; + } + + if (Game1.dayOfMonth == i + 1) + toSpeak += $", Current"; + + if (billboardQueryKey != toSpeak) + { + billboardQueryKey = toSpeak; + MainClass.ScreenReader.Say(toSpeak, true); + } + } + } + + private static void narrateDailyQuestBoard(Billboard __instance) + { + if (Game1.questOfTheDay == null || Game1.questOfTheDay.currentObjective == null || Game1.questOfTheDay.currentObjective.Length == 0) + { + // No quests + string toSpeak = "No quests for today!"; + if (billboardQueryKey != toSpeak) + { + billboardQueryKey = toSpeak; + MainClass.ScreenReader.Say(toSpeak, true); + } + } + else + { + SpriteFont font = ((LocalizedContentManager.CurrentLanguageCode == LocalizedContentManager.LanguageCode.ko) ? Game1.smallFont : Game1.dialogueFont); + string description = Game1.parseText(Game1.questOfTheDay.questDescription, font, 640); + string toSpeak = description; + + if (billboardQueryKey != toSpeak) + { + billboardQueryKey = toSpeak; + + // Snap to accept quest button + if (__instance.acceptQuestButton.visible) + { + toSpeak += "\t\n Left click to accept quest."; + __instance.acceptQuestButton.snapMouseCursorToCenter(); + } + + MainClass.ScreenReader.Say(toSpeak, true); + } + } + } + + internal static void Cleanup() + { + billboardQueryKey = ""; + } + } +} diff --git a/stardew-access/Patches/QuestPatches/QuestLogPatch.cs b/stardew-access/Patches/QuestPatches/QuestLogPatch.cs new file mode 100644 index 0000000..c93ddc1 --- /dev/null +++ b/stardew-access/Patches/QuestPatches/QuestLogPatch.cs @@ -0,0 +1,164 @@ +using StardewValley; +using StardewValley.Menus; +using StardewValley.Quests; + +namespace stardew_access.Patches +{ + // a.k.a. Journal Menu + internal class QuestLogPatch + { + internal static string questLogQuery = ""; + internal static bool isNarratingQuestInfo = false; + internal static bool firstTimeInIndividualQuest = true; + + internal static void DrawPatch(QuestLog __instance, int ___questPage, List> ___pages, int ___currentPage, IQuest ____shownQuest, List ____objectiveText) + { + try + { + int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position + + if (___questPage == -1) + { + narrateQuestList(__instance, ___pages, ___currentPage, x, y); + } + else + { + narrateIndividualQuest(__instance, ___currentPage, ____shownQuest, ____objectiveText, x, y); + } + } + catch (Exception e) + { + MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}"); + } + } + + private static void narrateQuestList(QuestLog __instance, List> ___pages, int ___currentPage, int x, int y) + { + string toSpeak = ""; + + if (!firstTimeInIndividualQuest) firstTimeInIndividualQuest = true; + + if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y)) + toSpeak = "Previous page button"; + else if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y)) + toSpeak = "Next page button"; + else if (__instance.upperRightCloseButton != null && __instance.upperRightCloseButton.visible && __instance.upperRightCloseButton.containsPoint(x, y)) + toSpeak = "Close menu button"; + else + { + for (int i = 0; i < __instance.questLogButtons.Count; i++) + { + if (___pages.Count() <= 0 || ___pages[___currentPage].Count() <= i) + continue; + + if (!__instance.questLogButtons[i].containsPoint(x, y)) + continue; + + string name = ___pages[___currentPage][i].GetName(); + int daysLeft = ___pages[___currentPage][i].GetDaysLeft(); + toSpeak = $"{name}"; + + if (daysLeft > 0 && ___pages[___currentPage][i].ShouldDisplayAsComplete()) + toSpeak += $"\t\n {daysLeft} days left"; + + toSpeak += ___pages[___currentPage][i].ShouldDisplayAsComplete() ? " completed!" : ""; + break; + } + } + + if (questLogQuery != toSpeak) + { + questLogQuery = toSpeak; + MainClass.ScreenReader.Say(toSpeak, true); + } + } + + private static void narrateIndividualQuest(QuestLog __instance, int ___currentPage, IQuest ____shownQuest, List ____objectiveText, int x, int y) + { + bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed(); + bool containsReward = __instance.HasReward() || __instance.HasMoneyReward(); + string description = Game1.parseText(____shownQuest.GetDescription(), Game1.dialogueFont, __instance.width - 128); + string title = ____shownQuest.GetName(); + string toSpeak = ""; + string extra = ""; + + if (firstTimeInIndividualQuest || (isPrimaryInfoKeyPressed && !isNarratingQuestInfo)) + { + if (firstTimeInIndividualQuest) + toSpeak = "Back button"; + + if (____shownQuest.ShouldDisplayAsComplete()) + { + #region Quest completed menu + + extra = $"Quest: {title} Completed!"; + + if (__instance.HasMoneyReward()) + extra += $"you recieved {____shownQuest.GetMoneyReward()}g"; + + #endregion + } + else + { + #region Quest in-complete menu + extra = $"Title: {title}. \t\n Description: {description}"; + + for (int j = 0; j < ____objectiveText.Count; j++) + { + string parsed_text = Game1.parseText(____objectiveText[j], width: __instance.width - 192, whichFont: Game1.dialogueFont); + if (____shownQuest != null && ____shownQuest is SpecialOrder) + { + OrderObjective order_objective = ((SpecialOrder)____shownQuest).objectives[j]; + if (order_objective.GetMaxCount() > 1 && order_objective.ShouldShowProgress()) + parsed_text += "\n\t" + order_objective.GetCount() + " of " + order_objective.GetMaxCount() + " completed"; + } + + extra += $"\t\nOrder {j + 1}: {parsed_text} \t\n"; + } + + if (____shownQuest != null) + { + int daysLeft = ____shownQuest.GetDaysLeft(); + + if (daysLeft > 0) + extra += $"\t\n{daysLeft} days left."; + } + #endregion + } + + isNarratingQuestInfo = true; + Task.Delay(200).ContinueWith(_ => { isNarratingQuestInfo = false; }); + questLogQuery = ""; + } + + if (!firstTimeInIndividualQuest) + { + if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y)) + toSpeak = (___currentPage > 0) ? "Previous page button" : "Back button"; + else if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y)) + toSpeak = "Next page button"; + else if (__instance.cancelQuestButton != null && __instance.cancelQuestButton.visible && __instance.cancelQuestButton.containsPoint(x, y)) + toSpeak = "Cancel quest button"; + else if (__instance.upperRightCloseButton != null && __instance.upperRightCloseButton.visible && __instance.upperRightCloseButton.containsPoint(x, y)) + toSpeak = "Close menu button"; + else if (containsReward && __instance.rewardBox.containsPoint(x, y)) + toSpeak = "Left click to collect reward"; + } + + if (firstTimeInIndividualQuest || (questLogQuery != toSpeak)) + { + questLogQuery = toSpeak; + MainClass.ScreenReader.Say(extra + " \n\t" + toSpeak, true); + + if (firstTimeInIndividualQuest) firstTimeInIndividualQuest = false; + } + } + + internal static void Cleaup() + { + questLogQuery = ""; + isNarratingQuestInfo = false; + firstTimeInIndividualQuest = true; + } + } +} diff --git a/stardew-access/Patches/QuestPatches/SpecialOrdersBoardPatch.cs b/stardew-access/Patches/QuestPatches/SpecialOrdersBoardPatch.cs new file mode 100644 index 0000000..eb27f5a --- /dev/null +++ b/stardew-access/Patches/QuestPatches/SpecialOrdersBoardPatch.cs @@ -0,0 +1,84 @@ +using StardewValley; +using StardewValley.Menus; + +namespace stardew_access.Patches +{ + internal class SpecialOrdersBoardPatch + { + private static string specialOrdersBoardQueryKey = ""; + + internal static void DrawPatch(SpecialOrdersBoard __instance) + { + try + { + int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position + + if (__instance.acceptLeftQuestButton.visible && __instance.acceptLeftQuestButton.containsPoint(x, y)) + { + string toSpeak = getSpecialOrderDetails(__instance.leftOrder); + + toSpeak = $"Left Quest:\n\t{toSpeak}\n\tPress left click to accept this quest."; + + Speak(toSpeak); + return; + } + + if (__instance.acceptRightQuestButton.visible && __instance.acceptRightQuestButton.containsPoint(x, y)) + { + string toSpeak = getSpecialOrderDetails(__instance.rightOrder); + + toSpeak = $"Right Quest:\n\t{toSpeak}\n\tPress left click to accept this quest."; + + Speak(toSpeak); + return; + } + } + catch (Exception e) + { + MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}"); + } + } + + private static string getSpecialOrderDetails(SpecialOrder order) + { + int daysLeft = order.GetDaysLeft(); + string description = order.GetDescription(); + string objectiveDescription = ""; + string name = order.GetName(); + int moneyReward = order.GetMoneyReward(); + + // Get each objectives + for (int i = 0; i < order.GetObjectiveDescriptions().Count; i++) + { + objectiveDescription += order.GetObjectiveDescriptions()[i] + ", \n"; + } + + string toReturn = $"{name}\n\tDescription:{description}\n\tObjectives: {objectiveDescription}"; + + if (order.IsTimedQuest()) + { + toReturn = $"{toReturn}\n\tTime: {daysLeft} days"; + } + + if (order.HasMoneyReward()) + { + toReturn = $"{toReturn}\n\tReward: {moneyReward}g"; + } + + return toReturn; + } + + private static void Speak(string toSpeak) + { + if (specialOrdersBoardQueryKey == toSpeak) return; + + specialOrdersBoardQueryKey = toSpeak; + MainClass.ScreenReader.Say(toSpeak, true); + } + + internal static void Cleanup() + { + specialOrdersBoardQueryKey = ""; + } + } +}